【 日常 】 多样伸展树 17年4月01日20:03 [ 3 ]

/* 前言: 好多天前准备记录下自己的坎坷修仙的点滴,以后希望能留下【珍贵的回忆】,萌新的日常代码,大佬互喷*/


这是我认为比较好的方法:

down - top  (AVL插入思路让我有的灵感)

/*--------------------------------------------------------------------------------
	前言: 伸展树自己敲的比较 low  所以参考了一下别人的思路,大致分成 4 种 
	1: top-down 自上而下的旋转(不需要结点保存父亲地址)【 非递归 】
	2: down-top 插入的函数的时候直接递归旋转(由书的AVL插入思路转变而来 )
	3: 比较尴尬没法描述,这个是书中的旋转方式,如果插入结点只有2个,那么直接 zig or zag 旋转
		  当结点数大于3时候每次 3个3个的双旋,自底而上
	4: 保存了父亲结点,通过结点中保存的父亲结点来进行操作
	但是对于最终的效果来说都是达到了的,都达到了查找结点做根的目的
----------------------------------------------------------------------------------*/
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>

struct treeNode
{
	int data;
	treeNode*pLeftChild;
	treeNode*pRightChild;
};
treeNode* InitTreeNode(treeNode*, int);
void TravalTreeNode(treeNode*);
treeNode* singleRotateLeft(treeNode*);
treeNode* singleRotateRight(treeNode*);
int main(void)
{
	treeNode*pRoot = NULL;	// 初始化
	pRoot = InitTreeNode(pRoot, 3);
	pRoot = InitTreeNode(pRoot, 8);
	pRoot = InitTreeNode(pRoot, 12);
	pRoot = InitTreeNode(pRoot, 6);
	pRoot = InitTreeNode(pRoot, 9);
	pRoot = InitTreeNode(pRoot, -1);
	pRoot = InitTreeNode(pRoot, 0);
	TravalTreeNode(pRoot);
	system("pause");
	return 0;
}
treeNode* InitTreeNode(treeNode*pRoot, int InitNum)
{
	if (!pRoot)
	{
		pRoot = (treeNode*)malloc(sizeof(treeNode));
		if (!pRoot)
		{
			printf("\n初始化根结点内存失败\n");
			exit(-1);
		}
		pRoot->data = InitNum;
		pRoot->pLeftChild = pRoot->pRightChild = NULL;
	}
	else if (InitNum < pRoot->data)         // 要插入数小于当前结点数 放左
	{
		pRoot->pLeftChild = InitTreeNode(pRoot->pLeftChild,InitNum);//左子树连接左递归
		pRoot = singleRotateLeft(pRoot);   //无条件左单旋转
	}
	else if (InitNum > pRoot->data)       // 要插入数大于当前结点数 放右
	{
		pRoot->pRightChild = InitTreeNode(pRoot->pRightChild,InitNum);//右子树连接右递归
		pRoot = singleRotateRight(pRoot);//无条件 右单旋转
	}
	/*-------------------------------------
	else 该数已有			 do nothing 
	--------------------------------------*/
	return pRoot;
}
void TravalTreeNode(treeNode*pRoot)
{
	if (!pRoot)
		return;
	TravalTreeNode(pRoot->pLeftChild);
	printf("%d\t", pRoot->data);
	TravalTreeNode(pRoot->pRightChild);
}
treeNode* singleRotateLeft(treeNode*pRoot)
{	//左左
	treeNode*pNewRoot = pRoot->pLeftChild;	  //新根是原来根的左孩子
	pRoot->pLeftChild = pNewRoot->pRightChild;//原根左指向新根右
	pNewRoot->pRightChild = pRoot;			//新根右指向原根
	return pNewRoot;			            //返回新根
}
treeNode* singleRotateRight(treeNode*pRoot)
{	//右右
	treeNode*pNewRoot = pRoot->pRightChild;	  //新根是原来根的右孩子
	pRoot->pRightChild = pNewRoot->pLeftChild;//原根右指向新根左
	pNewRoot->pLeftChild = pRoot;		    //新根左指向原根
	return pNewRoot;					    //返回新根
}
/*------------------------------------------------------------------------------------
后言:					这是我通过看书AVL而想出来的一种方法
					2: down - top 插入的函数的时候直接递归旋转
-------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------
当然也可直接插入,插入后将 return pRoot
				    改成 return pRoot=spalyingTreeNode(pRoot,InitNum)
					
	treeNode* spalyingTreeNode(treeNode*pRoot,int Num)
	{
		if (!pRoot||pRoot->data==Num)
			return pRoot;
		while (pRoot->data != Num)
		{
			if (pRoot->data > Num) //需要旋转的新根的值小于当前值
				pRoot = singleRotateLeft(pRoot); // 左单旋
			else
				pRoot = singleRotateRight(pRoot);
		}
		return pRoot;
	}
------------------------------------------------------------------------------------*/

4: 保存了父亲结点,通过结点中保存的父亲结点来进行操作

这种想法很好在下一个结点中保存了父亲结点的地址:
但是操作时发现其实好浪费步骤,每次旋转后都要修改父亲的地址,否则下次的旋转就会出错。
虽然修改父亲并不麻烦,但是好繁琐的感觉有木有 。QaQ 
如果有人有更好的操作求麻烦贴下代码学习,谢谢
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>
struct treeNode
{
	int data;
	treeNode*pLeftChild;
	treeNode*pRightChild;
	treeNode*pThisFather;
};
treeNode* InitTreeNode(treeNode*,treeNode*,int);
treeNode* spalyingTreeNode(treeNode*,treeNode*);
void TravelTreeNode(treeNode*);
treeNode* singleRotateLeft(treeNode*);
treeNode* singleRotateRight(treeNode*);
treeNode* reserchTreeNode(treeNode*,int);
void RevisepFather(treeNode*,treeNode*);

int main(void)
{
	treeNode*pRoot = NULL;
	treeNode*pNewRoot = NULL;
	pRoot = InitTreeNode(pRoot, NULL, 3); // 一根,二父,三值
	pRoot = InitTreeNode(pRoot, NULL, 8);		
	pRoot = InitTreeNode(pRoot, NULL, 12);	
	pRoot = InitTreeNode(pRoot, NULL, 6);	
	pRoot = InitTreeNode(pRoot, NULL, 9);	
	pRoot = InitTreeNode(pRoot, NULL, -1);		
	pRoot = InitTreeNode(pRoot, NULL, 0);	
	
	pNewRoot = reserchTreeNode(pRoot, 0);
	pRoot=spalyingTreeNode(pRoot, pNewRoot);
	RevisepFather(pRoot, NULL);		//重新修改树高
	TravelTreeNode(pRoot);
	system("pause");
	return 0;
}
treeNode* InitTreeNode(treeNode*pRoot, treeNode*pFather, int InitNum)
{
	if (!pRoot)
	{	// 根不存在
		pRoot = (treeNode*)malloc(sizeof(treeNode));
		if (!pRoot)
		{
			printf("\n根节点初始化内存失败\n");
			exit(-1);
		}
		pRoot->pLeftChild = pRoot->pRightChild = NULL;
		pRoot->pThisFather = pFather;// 左右空无父
		pRoot->data = InitNum;
	}
	else if (InitNum < pRoot->data)//插入值小于当前值
		pRoot->pLeftChild = InitTreeNode(pRoot->pLeftChild, pRoot, InitNum);
	else if (InitNum > pRoot->data)
		pRoot->pRightChild = InitTreeNode(pRoot->pRightChild, pRoot, InitNum);
	/*-----------------------------------------------
		else       已有               do   nothing
	------------------------------------------------*/
	return pRoot;
}
void TravelTreeNode(treeNode*pRoot)
{
	if (!pRoot)
		return;
	TravelTreeNode(pRoot->pLeftChild);
	printf("%d\t", pRoot->data);
	TravelTreeNode(pRoot->pRightChild);
}
treeNode* spalyingTreeNode(treeNode*pRoot,treeNode*pNewRoot)
{
	if (!pRoot||pRoot==pNewRoot)
		return pRoot;
	while (pRoot != pNewRoot)
	{
		if (pNewRoot->pThisFather->data > pNewRoot->data)//需要转的新根值小于父值	
		{
			if (pNewRoot->pThisFather->pThisFather == NULL)//(确定只有2个结点)
				pRoot = singleRotateLeft(pRoot);
			else
			{	// 说明结点层数大于等于3
				if (pNewRoot->pThisFather->pThisFather->data > pNewRoot->pThisFather->data)         //祖值大于父值
				{
					pNewRoot->pThisFather->pThisFather->pLeftChild = singleRotateLeft(pNewRoot->pThisFather);//父左单旋新根由祖左接收
					pNewRoot->pThisFather = pNewRoot->pThisFather->pThisFather;
				}
				else
				{
					pNewRoot->pThisFather->pThisFather->pRightChild = singleRotateLeft(pNewRoot->pThisFather);//父左单旋新根由祖右接收
					pNewRoot->pThisFather = pNewRoot->pThisFather->pThisFather;
				}
			}
		}
		else
		{	//需要旋转的新根的值大于父亲值	
			if (pNewRoot->pThisFather->pThisFather == NULL)//(确定只有2个结点)
				pRoot = singleRotateRight(pRoot);
			else
			{	// 说明结点层数大于等于3
				if (pNewRoot->pThisFather->pThisFather->data > pNewRoot->pThisFather->data)         //祖值大于父值
				{
					pNewRoot->pThisFather->pThisFather->pLeftChild = singleRotateRight(pNewRoot->pThisFather);//父右单旋新根由祖右接收
					pNewRoot->pThisFather = pNewRoot->pThisFather->pThisFather;
				}
				else
				{
					pNewRoot->pThisFather->pThisFather->pRightChild = singleRotateRight(pNewRoot->pThisFather);//父右单旋新根由祖左接收
					pNewRoot->pThisFather = pNewRoot->pThisFather->pThisFather;
				}
			}
		}
	}
	return pRoot;
}
treeNode* singleRotateLeft(treeNode*pRoot)
{	//左左
	treeNode*pNewRoot = pRoot->pLeftChild;	   //新根是原来根的左孩子
	pRoot->pLeftChild = pNewRoot->pRightChild; //原根左指向新根右
	pNewRoot->pRightChild = pRoot;			 //新根右指向原根
	return pNewRoot;                         //返回新根
}
treeNode* singleRotateRight(treeNode*pRoot)
{	//右右
	treeNode*pNewRoot = pRoot->pRightChild;	  //新根是原来根的右孩子
	pRoot->pRightChild = pNewRoot->pLeftChild;//原根右指向新根左
	pNewRoot->pLeftChild = pRoot;		    //新根左指向原根
	return pNewRoot;			            //返回新根
}
treeNode* reserchTreeNode(treeNode*pRoot,int ReserchNum)
{
	if (!pRoot)
		return NULL;
	if (pRoot->data == ReserchNum)
		return pRoot;
	else if (pRoot->data > ReserchNum)
		pRoot = reserchTreeNode(pRoot->pLeftChild, ReserchNum);
	else
		pRoot = reserchTreeNode(pRoot->pRightChild, ReserchNum);
	return pRoot;
}
void RevisepFather(treeNode*pRoot,treeNode*pFather)
{
	if (!pRoot)
		return;
	pRoot->pThisFather = pFather;
	RevisepFather(pRoot->pLeftChild, pRoot);
	RevisepFather(pRoot->pRightChild, pRoot);
}

ERROR  :下面的这个是错误的希望不要看

-----------------------------------------------------------------------------------------------

1: top - down 自上而下的旋转(不需要结点保存父亲地址)【 非递归 】

这种从上往下旋转也能达到效果,也蛮方便的,只需要提供 新根的地址一路旋就好

关键就这2个步骤【此方法博主很遗憾:是错误的如果 根12 左25 会发现无限循环左右】

-----------------------------------------------------------------------------------------------

treeNode*SplayingTreeNode(treeNode*pRoot, treeNode*pNewRoot)
{
	if (!pRoot || pRoot == pNewRoot)
		return pRoot;
	while (pRoot != pNewRoot)
	{
		if (pRoot->data > pNewRoot->data)//新根值小于当前值
			pRoot = singleRotateLeft(pRoot);
		else
			pRoot = singleRotateRight(pRoot);
	}
}
treeNode* reserchTreeNode(treeNode*pRoot, int ReserchNum)
{
	if (!pRoot)
		return NULL;
	if (pRoot->data == ReserchNum)
		return pRoot;
	else if (pRoot->data > ReserchNum)
		pRoot = reserchTreeNode(pRoot->pLeftChild, ReserchNum);
	else
		pRoot = reserchTreeNode(pRoot->pRightChild, ReserchNum);
	return pRoot;
}

书上的第三种很遗憾暂时没有很短的代码

我过去尝试敲了,但是很繁琐,代码也很烂 

希望这几天能修炼把第三种用简洁的方式写出来

--------------------------------------------------------------------------------------------------------

如果你看到了这里,博主也表示很遗憾,因为上面的方法基本都是很坑,能达到目的

但是效率很慢,而且上面的那个标注的是错误的。【就那一个错误的方法,不要介意】

----------------------------------------------------------------------------------------------------------------------------------

第三种也就是所谓的从底部一直向上旋转

分六种情况的:

虽然书中就分了3种,但是我敲的时候感觉就是6种

书中分

1: 旋转点pNewRoot 的父亲就是根(单旋)

2: zig-zig  " 一字型 "

3:zig-zag " 之字型 "

但我尝试敲了以后感觉是下面的六种(并查了一些资料维基百科也是6种)

1:zig 

2:zag (此2种为单旋的左右)

3:zig-zig

4:zig-zag ( 此2种为一字型 )

5:zig-zag

6:zag-zig ( 此2种为之字型 )

( 我个人认为 zig 左单旋 zag 右单旋  )


2017年4月2日20:20  今天从中午吃过饭一直换了很多方法尝试能从底部开始向上旋转

很无奈,都失败了,也去看了很多别人写的代码,没有一点头绪,最终结点中加上了父亲地址

而且代码写的比较尴尬,为了图省事在插入函数时就开始旋转,所以每次旋转后都会改变

父亲,只能插入一个纠正一下父亲的地址,而且在查找代码中用的while 比较繁琐

真诚的希望如果各位有好点的代码能私聊我,或者回复贴子,从1点一直到8点一直没停,不停的

换方法,但是自己的水平有限,实在想不出更好的方法

---------------------------------------------------------------------------------------------------

# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>

struct  treeNode
{
	int data;
	treeNode*pThisFather;	
	treeNode*pLeftChild;
	treeNode*pRightChild;
};

treeNode*InitTreeNode(treeNode*,treeNode*, int);
void travelTreeNode(treeNode*);
treeNode*SingleTotateLeft(treeNode*);
treeNode*SingleTotateRight(treeNode*);
treeNode*DoubleTotateLeft(treeNode*);
treeNode*DoubleTotateRight(treeNode*);
treeNode*Zig_zigTotateLeft(treeNode*);
treeNode*Zig_zigTotateRight(treeNode*);
treeNode*SplayingTreeNode(treeNode*,int);
void RevisTreeNodeFather(treeNode*,treeNode*);
treeNode*ReserchTreeNode(treeNode*, int);
int main(void)
{
	treeNode*pRoot = NULL;
	pRoot = InitTreeNode(pRoot, NULL,3);//插入
	RevisTreeNodeFather(pRoot, NULL);//修改父
	pRoot = InitTreeNode(pRoot, NULL,8);
	RevisTreeNodeFather(pRoot, NULL);
	pRoot = InitTreeNode(pRoot, NULL,9);
	RevisTreeNodeFather(pRoot, NULL);
	pRoot = InitTreeNode(pRoot, NULL,-1);
	RevisTreeNodeFather(pRoot, NULL);
	pRoot = InitTreeNode(pRoot, NULL,12);
	RevisTreeNodeFather(pRoot, NULL);
	pRoot = InitTreeNode(pRoot,NULL, 33);
	RevisTreeNodeFather(pRoot, NULL);
	pRoot = InitTreeNode(pRoot, NULL,2);
	RevisTreeNodeFather(pRoot, NULL);
	pRoot = SplayingTreeNode(pRoot, 8);
	travelTreeNode(pRoot);
	/*----------------------------------------------------------------
	很尴尬每次插入都要修复父亲(因为旋转和插入合并在一起写的)
	------------------------------------------------------------------*/
	system("pause");
	return 0;
}
treeNode*InitTreeNode(treeNode*pRoot,treeNode*pThisFather, int InitNum)
{
	static int FLAGE = 0;
	if (!pRoot)
	{
		pRoot = (treeNode*)malloc(sizeof(treeNode));
		if (!pRoot)
		{
			printf("\n初始化根节点内存失败\n");
			exit(-1);
		}
		pRoot->data = InitNum;
		pRoot->pLeftChild = pRoot->pRightChild = NULL;
		pRoot->pThisFather = pThisFather;
		FLAGE = 1;
	}
	else if (pRoot->data > InitNum)
	{	//插入值小当前值 左
		pRoot->pLeftChild = InitTreeNode(pRoot->pLeftChild,pRoot, InitNum);
		FLAGE++;
		if (pRoot->pThisFather || FLAGE == 3)		//该结点有父亲继续无直接旋
		{
			treeNode*pTemp = pRoot->pThisFather;//保存目前pRoot父亲地址
			if (FLAGE == 3)	//暗示在第三层
			{
				if (pRoot->pLeftChild->data > InitNum)	//一字左
					pRoot = Zig_zigTotateLeft(pRoot);
				else
					pRoot = DoubleTotateLeft(pRoot);//双旋左
				FLAGE = 1;	//恢复第一层计数
				pRoot->pThisFather = pTemp;
			}
		}
		else
			pRoot=SingleTotateLeft(pRoot);//单旋左
	}
	else if (pRoot->data < InitNum)
	{	//插入值大于当前值 右
		pRoot->pRightChild = InitTreeNode(pRoot->pRightChild,pRoot, InitNum);
		FLAGE++;
		if (pRoot->pThisFather || FLAGE == 3)	//该结点的父亲存在继续无直接旋
		{
			treeNode*pTemp = pRoot->pThisFather;//保存目前pRoot父亲地址
			if (FLAGE == 3)//暗示在第三层
			{
				if (pRoot->pRightChild->data < InitNum)//一字右
					pRoot = Zig_zigTotateRight(pRoot);
				else
					pRoot = DoubleTotateRight(pRoot);
				FLAGE = 1;//恢复第一层计数
				pRoot->pThisFather = pTemp;
			}
		}
		else
			pRoot = SingleTotateRight(pRoot);
	}
	/*------------------------------------------------
				else  已有           do nothing
	------------------------------------------------*/
	return pRoot;
}
void travelTreeNode(treeNode*pRoot)
{
	if (!pRoot)
		return;
	travelTreeNode(pRoot->pLeftChild);
	printf("%d\t", pRoot->data);
	travelTreeNode(pRoot->pRightChild);
}
treeNode* SingleTotateLeft(treeNode*pRoot)
{	//左单旋
	treeNode*pNewRoot = pRoot->pLeftChild;
	pRoot->pLeftChild = pNewRoot->pRightChild;
	pNewRoot->pRightChild = pRoot;
	return pNewRoot;
}
treeNode* SingleTotateRight(treeNode*pRoot)
{	//右单旋
	treeNode*pNewRoot = pRoot->pRightChild;
	pRoot->pRightChild = pNewRoot->pLeftChild;
	pNewRoot->pLeftChild = pRoot;
	return pNewRoot;
}
treeNode*DoubleTotateLeft(treeNode*pRoot)
{	//左双旋
	pRoot->pLeftChild = SingleTotateRight(pRoot->pLeftChild);
	return SingleTotateLeft(pRoot);
}
treeNode*DoubleTotateRight(treeNode*pRoot)
{	//右双旋
	pRoot->pRightChild = SingleTotateLeft(pRoot->pRightChild);
	return SingleTotateRight(pRoot);
}
treeNode*Zig_zigTotateLeft(treeNode*pRoot)
{	// 一字左
	pRoot = SingleTotateLeft(pRoot);
	return SingleTotateLeft(pRoot);
}
treeNode*Zig_zigTotateRight(treeNode*pRoot)
{	//一字右
	pRoot = SingleTotateRight(pRoot);
	return SingleTotateRight(pRoot);
}
treeNode*ReserchTreeNode(treeNode*pRoot, int ReserchNum)
{
	if (!pRoot || pRoot->data == ReserchNum)
		return pRoot;
	while (pRoot&&pRoot->data != ReserchNum)//当前结点存在并且值不等于查找值
	{
		if (pRoot->data > ReserchNum)//左
			pRoot = pRoot->pLeftChild;
		else
			pRoot = pRoot->pRightChild;
	}
	return pRoot;
}
treeNode*SplayingTreeNode(treeNode*pRoot, int SplayingNum)
{
	if (!pRoot || pRoot->data == SplayingNum)
		return pRoot;
	treeNode*pNewRoot = ReserchTreeNode(pRoot, SplayingNum);
	treeNode*pGrandFather, *pFather;
	while (pRoot != pNewRoot)//只要不和根同一直转
	{
			if (pRoot->pLeftChild == pNewRoot)//就2个结点
				pRoot = SingleTotateLeft(pRoot);//单旋左
			else if (pRoot->pRightChild == pNewRoot)//就2个结点
				pRoot = SingleTotateRight(pRoot);//单旋右
			else//大于等于3个
			{
				pFather = pNewRoot->pThisFather;
				pGrandFather = pFather->pThisFather;
				if (pGrandFather->data > pFather->data)//祖>父
				{//左
					if (pFather->data > pNewRoot->data)//父>孙
					{	//一字左
						if (pGrandFather->pThisFather)//祖的父存在
						{
							treeNode*pDGrandFather = pGrandFather->pThisFather;//祖的父
							if (pDGrandFather->data > pGrandFather->data)//祖的父>祖(左)
								pDGrandFather->pLeftChild = Zig_zigTotateLeft(pGrandFather);
							else
								pDGrandFather->pRightChild = Zig_zigTotateLeft(pGrandFather);
							pNewRoot->pThisFather = pDGrandFather;//修改父亲
						}
						else
							pRoot = Zig_zigTotateLeft(pRoot);//就 3 个结点
					}
					else
					{	//父<孙(双旋左)
						if (pGrandFather->pThisFather)
						{
							treeNode*pDGrandFather = pGrandFather->pThisFather;//祖的父
							if (pDGrandFather->data > pGrandFather->data)//祖的父>祖(左)
								pDGrandFather->pLeftChild = DoubleTotateLeft(pGrandFather);
							else
								pDGrandFather->pRightChild = DoubleTotateLeft(pGrandFather);
							pNewRoot->pThisFather = pDGrandFather;//修改父亲
						}
						else
							pRoot = DoubleTotateLeft(pRoot);
					}
				}
				else//祖<父
				{//右
					if (pFather->data < pNewRoot->data)//父<孙
					{	//一字右
						if (pGrandFather->pThisFather)
						{
							treeNode*pDGrandFather = pGrandFather->pThisFather;//祖的父
							if (pDGrandFather->data < pGrandFather->data)
								pDGrandFather->pRightChild = Zig_zigTotateRight(pGrandFather);
							else
								pDGrandFather->pLeftChild = Zig_zigTotateRight(pGrandFather);
							pNewRoot->pThisFather = pDGrandFather;//修改父
						}
						else
							pRoot = Zig_zigTotateRight(pRoot);
					}
					else//父>孙
					{	//双旋右
						if (pGrandFather->pThisFather)
						{
							treeNode*pDGrandFather = pGrandFather->pThisFather;//祖的父
							if (pDGrandFather->data < pGrandFather->data)
								pDGrandFather->pRightChild = DoubleTotateRight(pGrandFather);
							else
								pDGrandFather->pLeftChild = DoubleTotateRight(pGrandFather);
							pNewRoot->pThisFather = pDGrandFather;//修改父
						}
						else
							pRoot = DoubleTotateRight(pRoot);
					}
				}
			}
	}
	return pRoot;
}
void RevisTreeNodeFather(treeNode*pRoot,treeNode*pFather)
{
	if (!pRoot)
		return;
	pRoot->pThisFather = pFather;
	RevisTreeNodeFather(pRoot->pLeftChild, pRoot);
	RevisTreeNodeFather(pRoot->pRightChild, pRoot);
}


/*-------------------------------------------------------------------
2017年4月4日16:03:34

今天心态很爆炸,连续炸了几个了,这个是最后一种,第五种

总结随便对于各种方法的实现来说作者给的方法实在是坑,但是对于
效率来说,作者的效率最高,因为从top-down 会出现本来升上去的
旋转后又被降了下来,但是对于down-top来说,要做根的则一直是
在上升旋转的 

--------------------------------------------------------------------*/

# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>

struct TreeNode
{
	int data;
	TreeNode*pLeftChild;
	TreeNode*pRightChild;
};

TreeNode*InitTreeNode(TreeNode*, int);
void TrevalTreeNode(TreeNode*);
void ReserchPosition(TreeNode*&,int);
void SpalyingTreeNode(TreeNode*&,TreeNode*);
TreeNode*SingleRotateLeft(TreeNode*);
TreeNode*SingleRotateRight(TreeNode*);
TreeNode*DoubleRotateLeft(TreeNode*);
TreeNode*DoubleRotateRight(TreeNode*);
TreeNode*Zig_zigTotateLeft(TreeNode*);
TreeNode*Zig_zigTotateRight(TreeNode*);
int main(void)
{
	TreeNode*pRoot = NULL;
	pRoot = InitTreeNode(pRoot, 20);
	pRoot = InitTreeNode(pRoot, 10);
	pRoot = InitTreeNode(pRoot, 30);
	pRoot = InitTreeNode(pRoot, 1);
	pRoot = InitTreeNode(pRoot, 22);
	pRoot = InitTreeNode(pRoot, 11);
	pRoot = InitTreeNode(pRoot, 13);
	pRoot = InitTreeNode(pRoot, 15);
	pRoot = InitTreeNode(pRoot, 14);
	printf("\n第一次遍历【未旋】:\n");
	TrevalTreeNode(pRoot);
	printf("\n第二次遍历【旋转】:\n");
	ReserchPosition(pRoot, 14);
	TrevalTreeNode(pRoot);
	system("pause");
	return 0;
}
TreeNode*InitTreeNode(TreeNode*pRoot,int InitNum)
{
	if (!pRoot)
	{
		pRoot = (TreeNode*)malloc(sizeof(TreeNode));
		if (!pRoot)
		{
			printf("\nERROR:Out of Space\n");
			exit(-1);
		}
		pRoot->data = InitNum;
		pRoot->pLeftChild = pRoot->pRightChild = NULL;
	}
	else if (pRoot->data > InitNum)//当前值大于插入值
		pRoot->pLeftChild = InitTreeNode(pRoot->pLeftChild, InitNum);
	else if (pRoot->data < InitNum)
		pRoot->pRightChild = InitTreeNode(pRoot->pRightChild, InitNum);
	/*---------------------------------
		else  已有    do nothing 
	----------------------------------*/
	return pRoot;
}
void TrevalTreeNode(TreeNode*pRoot)
{
	if (!pRoot)
		return;
	TrevalTreeNode(pRoot->pLeftChild);
	printf("%d\t", pRoot->data);
	TrevalTreeNode(pRoot->pRightChild);
}
void ReserchPosition(TreeNode*&pRoot, int ReserchNum)
{
	TreeNode*pSentinelONE = pRoot;
	TreeNode*pSentinelTWO = pRoot;
	while (pSentinelONE&&pSentinelONE->data != ReserchNum)//哨兵存在且不等于要查找的数字
	{
		pSentinelTWO = pSentinelONE;//哨兵二留在原地
		if (pSentinelONE->data == ReserchNum)
			break;	//找到跳出
		else if (pSentinelONE->data > ReserchNum)//当前值>查找值
			pSentinelONE = pSentinelONE->pLeftChild;
		else
			pSentinelONE = pSentinelONE->pRightChild;
	}
	if (pSentinelONE)	
		SpalyingTreeNode(pRoot, pSentinelONE);//找到 哨兵一 旋转一
	else
		SpalyingTreeNode(pRoot, pSentinelTWO);//否则转二
}
void SpalyingTreeNode(TreeNode*&pRoot,TreeNode*pNewRoot)//晕查找到的时候就旋转而不是要旋转的时候查找
{
	while (pRoot != pNewRoot)
	{
		if (pRoot->data > pNewRoot->data)//当前值>新根值
		{
			if (pRoot->pLeftChild != pNewRoot)//暗示结点数>=3
			{
				if (pRoot->pLeftChild->data > pNewRoot->data)//左左左"一字左"
					pRoot = Zig_zigTotateLeft(pRoot);
				else
					pRoot = DoubleRotateLeft(pRoot);//左左右 “zig-zag”
			}
			else
				pRoot = SingleRotateLeft(pRoot);//只有2个节点的单旋左
		}
		else//右边
		{	
			if (pRoot->pRightChild != pNewRoot)//暗示结点数>=3
			{
				if (pRoot->pRightChild->data < pNewRoot->data)//右右右“一字右”
					pRoot = Zig_zigTotateRight(pRoot);
				else
					pRoot = DoubleRotateRight(pRoot);//右右左“zag-zig”
			}
			else
				pRoot = SingleRotateRight(pRoot);//单旋右
		}
	}
}
TreeNode*SingleRotateLeft(TreeNode*pRoot)
{
	TreeNode*pNewRoot = pRoot->pLeftChild;
	pRoot->pLeftChild = pNewRoot->pRightChild;
	pNewRoot->pRightChild = pRoot;
	return pNewRoot;
}
TreeNode*SingleRotateRight(TreeNode*pRoot)
{
	TreeNode*pNewRoot = pRoot->pRightChild;
	pRoot->pRightChild = pNewRoot->pLeftChild;
	pNewRoot->pLeftChild = pRoot;
	return pNewRoot;
}
TreeNode*DoubleRotateLeft(TreeNode*pRoot)
{
	pRoot->pLeftChild = SingleRotateRight(pRoot->pLeftChild);
	return SingleRotateLeft(pRoot);
}
TreeNode*DoubleRotateRight(TreeNode*pRoot)
{
	pRoot->pRightChild = SingleRotateLeft(pRoot->pRightChild);
	return SingleRotateRight(pRoot);
}
TreeNode*Zig_zigTotateLeft(TreeNode*pRoot)
{
	pRoot = SingleRotateLeft(pRoot);
	return SingleRotateLeft(pRoot);
}
TreeNode*Zig_zigTotateRight(TreeNode*pRoot)
{
	pRoot = SingleRotateRight(pRoot);
	return SingleRotateRight(pRoot);
}

-------------------------------------------------------------------------

2017年4月16日21:43  更新

如果你看到了这里,博主很感谢你的支持,上面的从6种

旋转方法的开始都是常见的,之前的修炼有误,博主瞎想

瞎带节奏,带偏了,虽然能达到目的但是不合适

下面的是真正的【高级数据结构】的 伸展树,在书中介绍的是

依旧的三种只不过旋转方式变了,不在是旋转,而是切割

至少我理解吧,我理解是切割 ,切割下来的部分用 【L】【R】

来连接,这才是正正的 Top-Down

【注:】书中介绍了三种旋转镜像就是6种,但是也同样说了其实双旋就是

2次单旋切割,所以书中 的代码只用了2中表示,但是我为了理解还是写了6种

感觉还是不太完美,废话少说,上代码

【如果不知道旋转方式建议去看下图,和原来的方式不同,不在是旋转,而是 切割!】

-------------------------------------------------------------------------

/*	
		尚未发现书中使用 NullNOde 的优点,所以初次试敲不会使用 NullNode 直接使用 NULL , 会使用 Header 来包含 L R 
*/
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>

struct TreeNode
{
	int data;
	TreeNode*pLeftChild;
	TreeNode*pRightChild;
};

TreeNode* MakeEmpty(TreeNode*);//清空内存
TreeNode* FindTreeNode(TreeNode*, int);//结点查找
TreeNode* FindMin(TreeNode*);
TreeNode* FindMax(TreeNode*);
TreeNode* SplayTreeNode(TreeNode*, int );//伸展
TreeNode* InitTreeNode(TreeNode*, int);//初始化树
TreeNode* InsertTreeNode(TreeNode*, int);//插入
TreeNode* DeleteTreeNode(TreeNode*, int);//删除
void TrevalTreeNode(TreeNode*);//遍历
TreeNode*SingleTotateLeft(TreeNode*, TreeNode*&);//左单旋(切割)
TreeNode*SingleTotateRight(TreeNode*, TreeNode*&);//右单旋(切割)
TreeNode*DoubleTotateLeft(TreeNode*, TreeNode*&, TreeNode*&);//左双旋(切割)
TreeNode*DoubleTotateRight(TreeNode*, TreeNode*&, TreeNode*&);//右双旋(切割) 
TreeNode*Zig_zigTotate_Left(TreeNode*, TreeNode*&);//一字左切割(简化)【注:非简化需要加上一次(普通)的左单旋】
TreeNode*Zag_zagTotate_Right(TreeNode*, TreeNode*&);//一字右切割(简化)
int main(void)
{
	TreeNode*pRoot = NULL;
	pRoot = InitTreeNode(pRoot, 3);
	pRoot = InsertTreeNode(pRoot, 5);
	pRoot = InsertTreeNode(pRoot, 8);
	pRoot = InsertTreeNode(pRoot, 6);
	pRoot = InsertTreeNode(pRoot, 7);
	pRoot = InsertTreeNode(pRoot, 4);
	pRoot = InsertTreeNode(pRoot, 1);
	pRoot = InsertTreeNode(pRoot, 0);
	pRoot = InsertTreeNode(pRoot, 12);
	pRoot = InsertTreeNode(pRoot, 13);
	pRoot = InsertTreeNode(pRoot, 2);
	pRoot = InsertTreeNode(pRoot, 10);
	printf("\n初次遍历:\n");
	TrevalTreeNode(pRoot);
	printf("\n删除结点:\n");
	pRoot = DeleteTreeNode(pRoot, 3);
	TrevalTreeNode(pRoot);
	printf("\n查找结点:\n");
	pRoot=FindTreeNode(pRoot, 0);
	printf("查找值:%d\n", pRoot->data);
	TrevalTreeNode(pRoot);
	printf("\n最大结点:\n");
	pRoot=FindMax(pRoot);
	printf("最大值:%d", pRoot->data);
	printf("\n最小结点:\n");
	pRoot = FindMin(pRoot);
	printf("最小值:%d", pRoot->data);
	
	printf("\n\n");
	system("pause");
	return 0;
}
TreeNode* InitTreeNode(TreeNode*pRoot,int InitNum)
{
	if (!pRoot)
	{
		pRoot = (TreeNode*)malloc(sizeof(TreeNode));
		if (!pRoot)
		{
			printf("\nERROR:Out of Space \n");
			exit(-1);
		}
		pRoot->data = InitNum;
		pRoot->pLeftChild = pRoot->pRightChild = NULL;
	}
	return pRoot;
}
TreeNode* InsertTreeNode(TreeNode*pRoot, int InsertNum)
{
	if (!pRoot)
		return pRoot;
	TreeNode*pNewNode = (TreeNode*)malloc(sizeof(TreeNode));
	if (!pNewNode)
	{
		printf("\nERROR:Out of Space \n");
		exit(-1);
	}
	pNewNode->data = InsertNum;
	pNewNode->pLeftChild = pNewNode->pRightChild = NULL;
	pRoot = SplayTreeNode(pRoot, InsertNum);//将最接近插入值的结点展开上来
	/*---------------------------------------------------------
		保持一个原则:被旋转上来的值【无限】接近插入值
	----------------------------------------------------------*/
	if (InsertNum == pRoot->data)//插入值已经有了
		free(pNewNode);
	else if (InsertNum < pRoot->data)
	{
		pNewNode->pLeftChild = pRoot->pLeftChild;
		pNewNode->pRightChild = pRoot;
		pRoot->pLeftChild = NULL;
		pRoot = pNewNode;
	}
	else
	{
		pNewNode->pLeftChild = pRoot;
		pNewNode->pRightChild = pRoot->pRightChild;
		pRoot->pRightChild = NULL;
		pRoot = pNewNode;
	}
	return pRoot;
}
TreeNode* SplayTreeNode(TreeNode*pRoot,int SplayingNum)
{
	if (!pRoot)
		return pRoot;
	TreeNode Header;	//利用Header 的结点来充当 L R 的集合 
	Header.pLeftChild = Header.pRightChild = NULL;// L->Right  R->Left
	//  TreeNode*pLeftChildMax = NULL; TreeNode*pRightChildMin = NULL;  兼并的当前节点 会产生更多的判断步骤 	
	TreeNode*pLeftChildMax, *pRightChildMin;
	pLeftChildMax = pRightChildMin = &Header;
	while (SplayingNum != pRoot->data)
	{
		if (SplayingNum<pRoot->data)//旋转数<祖
		{
			if (pRoot->pLeftChild)//父亲存在
			{
				if (SplayingNum < pRoot->pLeftChild->data)//小于父亲
				{//这时候只能确定有2个结点
					if (pRoot->pLeftChild->pLeftChild)//父亲的左孩子存在
						pRoot = Zig_zigTotate_Left(pRoot, pRightChildMin);//一字左(孙做根)
					else//父亲没有左孩子,父亲就是旋转后的根
						pRoot = SingleTotateLeft(pRoot, pRightChildMin);//单旋左(父做根)
				}
				else if (SplayingNum > pRoot->pLeftChild->data)//大于父亲
				{
					if (pRoot->pLeftChild->pRightChild)//父亲的右孩子存在
						pRoot = DoubleTotateLeft(pRoot, pLeftChildMax, pRightChildMin);//双旋左(孙做根)
					else//父亲没有右孩子
						pRoot = SingleTotateLeft(pRoot, pRightChildMin);//单旋左(父做根)
				}
				else//旋转数等于父亲
					pRoot = SingleTotateLeft(pRoot, pRightChildMin);//单旋左(父亲做根)
			}
			else//父亲不存在
				break;//当前就是旋转后的根 直接跳出 
		}
		else//旋转数>祖
		{
			if (pRoot->pRightChild)//父亲存在
			{
				if (SplayingNum < pRoot->pRightChild->data)//小于父亲
				{
					if (pRoot->pRightChild->pLeftChild)//父亲的左孩子存在
						pRoot = DoubleTotateRight(pRoot, pLeftChildMax, pRightChildMin);//双旋右(孙做根)
					else//父亲没有左孩子
						pRoot = SingleTotateRight(pRoot, pLeftChildMax);//单旋右(父亲做根)
				}
				else if (SplayingNum > pRoot->pRightChild->data)//大于父亲
				{
					if (pRoot->pRightChild->pRightChild)//父亲的有右孩子
						pRoot = Zag_zagTotate_Right(pRoot, pLeftChildMax);//一字右(孙做根)
					else//父亲没有右孩子
						pRoot = SingleTotateRight(pRoot, pLeftChildMax);//单旋右(父亲做根)
				}
				else
					pRoot = SingleTotateRight(pRoot, pLeftChildMax);//单旋右( 父做根 )
			}
			else//父亲不存在
				break; //当前就是旋转后的根 直接跳出
		}
	}//while(SplayingNum!=pRoot->data)
	/*-==---------------
		开始合并 L R T
	--------------------*/
	pLeftChildMax->pRightChild = pRoot->pLeftChild;
	pRightChildMin->pLeftChild = pRoot->pRightChild;
	pRoot->pLeftChild = Header.pRightChild;
	pRoot->pRightChild = Header.pLeftChild;
	return pRoot;
}
TreeNode* DeleteTreeNode(TreeNode*pRoot,int DeleteNum)
{
	if (!pRoot)
		return pRoot;
	TreeNode*pNewRoot = NULL;
	pRoot=SplayTreeNode(pRoot, DeleteNum);//将要删除的数展开上来
	if (pRoot->data == DeleteNum)
	{
		if (!pRoot->pLeftChild)
		{
			pNewRoot = pRoot->pRightChild;
			free(pRoot);
			pRoot = pNewRoot;
		}
		else
		{
			pNewRoot = SplayTreeNode(pRoot->pLeftChild, DeleteNum);//将左子树最接近删除值的数字展开上来
			pNewRoot->pRightChild = pRoot->pRightChild;//展开上来的新根一定没有右子树因为如果有右子树那么他就不会做新根(左子树最大值)
			free(pRoot);
			pRoot = pNewRoot;
		}
	}
	return pRoot;
}
TreeNode* FindTreeNode(TreeNode*pRoot, int FindNum)
{
	if (!pRoot)
		return pRoot;
	return SplayTreeNode(pRoot, FindNum);
}
TreeNode* FindMin(TreeNode*pRoot)
{
	if (!pRoot)
		return pRoot;
	TreeNode*pSentinel = pRoot;
	while (pSentinel->pLeftChild)
		pSentinel = pSentinel->pLeftChild;
	return SplayTreeNode(pRoot, pSentinel->data);
}
TreeNode* FindMax(TreeNode*pRoot)
{
	if (!pRoot)
		return pRoot;
	TreeNode*pSentinel = pRoot;
	while (pSentinel->pRightChild)
		pSentinel = pSentinel->pRightChild;
	return SplayTreeNode(pRoot, pSentinel->data);
}
TreeNode* MakeEmpty(TreeNode*pRoot)
{
	pRoot->pLeftChild = MakeEmpty(pRoot->pLeftChild);
	pRoot->pRightChild = MakeEmpty(pRoot->pRightChild);
	if (!pRoot->pLeftChild && !pRoot->pRightChild)
		free(pRoot);
	return NULL;
}
void TrevalTreeNode(TreeNode*pRoot)
{
	if (!pRoot)
		return;
	TrevalTreeNode(pRoot->pLeftChild);
	printf("%d\t", pRoot->data);
	TrevalTreeNode(pRoot->pRightChild);
}
TreeNode*SingleTotateLeft(TreeNode*pRoot,TreeNode*&pChild)
{
	TreeNode*pNewRoot = pRoot->pLeftChild;//标记孩子
	pRoot->pLeftChild = NULL;//割断
	pChild->pLeftChild = pRoot;//R->Left 连接
	pChild = pRoot;// Rmin=pRoot
	return pNewRoot;
}
TreeNode*SingleTotateRight(TreeNode*pRoot, TreeNode*&pChild)
{
	TreeNode*pNewRoot = pRoot->pRightChild;
	pRoot->pRightChild = NULL;
	pChild->pRightChild = pRoot;
	pChild = pRoot;
	return pNewRoot;
}
TreeNode*DoubleTotateLeft(TreeNode*pRoot, TreeNode*&pLeftChild, TreeNode*&pRightChild)
{
	pRoot = SingleTotateLeft(pRoot, pRightChild);
	return SingleTotateRight(pRoot, pLeftChild);
}
TreeNode*DoubleTotateRight(TreeNode*pRoot, TreeNode*&pLeftChild, TreeNode*&pRightChild)
{
	pRoot = SingleTotateRight(pRoot, pLeftChild);
	return SingleTotateLeft(pRoot, pRightChild);
}
TreeNode*Zig_zigTotate_Left(TreeNode*pRoot,TreeNode*&pChild)
{
	pRoot = SingleTotateLeft(pRoot, pChild);
	return SingleTotateLeft(pRoot, pChild);
}
TreeNode*Zag_zagTotate_Right(TreeNode*pRoot, TreeNode*&pChild)
{
	pRoot = SingleTotateRight(pRoot, pChild);
	return SingleTotateRight(pRoot, pChild);
}


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值