關於二叉樹的相關操作彙總

關於二叉樹的相關操作彙總,其中包含以下操作:

  1. 遞歸前序遍歷
  2. 非遞歸前序遍歷
  3. 遞歸中序遍歷
  4. 非遞歸中序遍歷
  5. 遞歸後序遍歷
  6. 非遞歸後序遍歷
  7. 遞歸層次遍歷
  8. 非遞歸層次遍歷
  9. 遞歸計算二叉樹的高度
  10. 非遞歸計算二叉樹高度
  11. 遞歸查找某點在二叉樹的那一層
  12. 非遞歸查找某點在二叉樹的那一層
  13. 判斷兩棵二叉樹是否相似
  14. 判斷二叉樹是不是完全二叉樹
  15. 輸出某一結點的到跟結點的路徑
  16. 得到兩個結點的最近的共同祖先
  17. 拆分二叉樹
  18. 統計二叉樹的結點個數
  19. 線索中序二叉樹的建立
  20. 線索中序二叉樹的輸出
  21. 根據前序和中序非遞歸建立二叉樹
  22. 根據前序和中序遞歸建立二叉樹

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

#define MAX_SIZE 100

typedef struct BiTNode{
	char data;
	struct BiTNode *lchild, *rchild;
}BiTNode,*BiTree;


typedef struct BiTNodeTag{
	BiTNode *btnode;
	int tag;
}BiTNodeTag;

typedef struct BiThrNode{
	char data;
	struct BiThrNode *lchild, *rchild;
	int ltag,rtag;
}BiThrNode;


BiTNode *mallocTreeNode(char p){
	BiTNode *temp = (BiTNode *) malloc(sizeof(BiTNode));
	temp->data = p;
	temp ->lchild = NULL;
	temp->rchild = NULL;
	return temp;
}

void printNodeData(BiTNode *nod){
	printf("%c",nod->data);

}
//遞歸建立二叉樹
void createBiTree(BiTree &t){
	char ch;

	scanf("%c",&ch);


	if (ch == ' '){
		t = NULL;
		return;
	} 

	if (!(t = (BiTree)malloc(sizeof(BiTNode)))){
		exit(1);
	}

	t->data = ch;
	printf("the data is %c\n",ch);
	createBiTree(t->lchild);
	createBiTree(t->rchild);
}
//非遞歸建立二叉樹
BiTNode *createBiTree(){

	//char str[] ="ABC@G@@@DE@@F@I";
	//char str[] ="ABC@G@@@DE@@@";
	//char str[] ="ABJK@@IC@G@@@";
	char str[] ="ABC@G@@@DE@@@";
	//char str[] ="ABC@G@@";
	//char str[] ="A@B@";
	//char str[] ="AB@@C@";
	//char str[] ="A@B@C@";
	char *p = str;

	BiTNode * stack[MAX_SIZE];
	int top = -1;

	BiTNode *pTree = NULL;
	BiTNode *rootNode = NULL;

	int isRightTree = 0;

	if (*p == '@'){
		printf("空二叉樹");
		exit(0);
	}
	//根節點入棧
	pTree = mallocTreeNode(*p);
	p++;
	stack[++top] = pTree;
	rootNode = pTree;
	
	while (*p){

		if (*p != '@'){

			if (isRightTree){

				BiTNode *temp = mallocTreeNode(*p);
				pTree->rchild = temp;
				pTree = temp;
				//入棧
				stack[++top] = pTree;
				//因爲每次只能執行一次向右插入操作
				isRightTree = 0;

			} else {
				BiTNode *temp = mallocTreeNode(*p);
				pTree->lchild = temp;
				pTree = temp;
				//入棧
				stack[++top] = pTree;
			}

		} else {
			if (top == -1){
				break;
			} else {
				pTree = stack[top--];
			}
			if (!isRightTree){
				//等於@時退棧,同時向右子樹插入
				isRightTree = 1;
			}
		}

		p++;
	}
	
	return rootNode;

}
//遞歸前序遍歷
void preOrderTraverse(BiTree t){

	if (t!= NULL){
		printNodeData(t);
		preOrderTraverse(t->lchild);
		preOrderTraverse(t->rchild);

	}

}
//非遞歸前序遍歷1
void preOrderTraverse1(BiTree t){
	
	BiTNode *stack[MAX_SIZE];
	int top = -1;

	printNodeData(t);
	BiTNode* temp = t;
	stack[++top] = t;
	t = t->lchild;

	while(top > -1){

		if (t != NULL){
			printNodeData(t);
			stack[++top] = t;
			t = t->lchild;
		}else{
			//退棧操作的原因:左子樹爲空,右子樹爲空,在左子樹爲空時,直接進入退棧程序,退到上層之後訪問右子樹。
			//在右子樹爲空時,說明本層的程序已經完成操作,需要退到上層繼續進行操作。
			//這時候就考慮是訪問左子樹還是右子樹,因爲程序本身是訪問了左子樹之後進棧的,因此退棧後應訪問右子樹。
			t = stack[top--];
			//當出棧的結點爲頭結點時,因爲頭結點退棧之後,整個棧就爲空了。因此需要判斷。
			if (temp == t){
				t = t->rchild;
				//判斷右子樹是否爲空。
				if (t != NULL){
					//不爲空,則進棧
					stack[++top] = t;
					continue;
				} else{
					//爲空,結束循環
					break;
				}
			}
			t = t->rchild;
		}
	}
}
//非遞歸前序遍歷2
void preOrderTraverse2(BiTree p){

	BiTNode *stack[MAX_SIZE];
	int top = -1;
	//將棧值和當前結點一起判斷,簡化了前一個方法。
	while(top > -1 || p != NULL){

			if (p != NULL){
				printNodeData(p);
				stack[++top] = p;
				p = p->lchild;
			} else {
				p = stack[top--];
				p = p->rchild;           
			}
	}

}
//非遞歸前序遍歷3
void preOrderTraverse3(BiTree p){

	BiTNode *stack[MAX_SIZE];
	int top = -1;
	stack[++top] = p;
	while(top >-1){
		p = stack[top--];
		printNodeData(p);
		if(p->rchild != NULL){

			stack[++top] = p->rchild;    
		}  
		if(p->lchild != NULL){

			stack[++top] = p->lchild;    
		}  

	}
}

//遞歸中序遍歷
void inOrderTraverse(BiTree t){

	if (t != NULL){
		inOrderTraverse(t->lchild);
		printNodeData(t);
		inOrderTraverse(t->rchild);
	}

}
//非遞歸中序遍歷
void inOrderTraverse1(BiTree t){

	BiTNode *stack[MAX_SIZE];
	int top = -1;

	BiTNode * temp = t;	

	while(top > -1 || t != NULL){
		while(t != NULL){
			stack[++top] = t;
			t = t->lchild;
		}
		t = stack[top--];
		printNodeData(t);
		t = t->rchild;
		
	}

}
//遞歸後序遍歷
void postOrderTraverse(BiTree t){
	if (t != NULL){
		postOrderTraverse(t->lchild);
		postOrderTraverse(t->rchild);
		printNodeData(t);
	}

}
//非遞歸後序遍歷1,每個結點加一個標誌位,表示該結點是第幾次在棧頂。如果是第二次則可以輸出了。如果不是,則需要訪問其右子樹。
/************************************************************************/
/* 對於任一結點P,將其入棧,然後沿其左子樹一直往下搜索,直到搜索到沒有左孩子的結點,此時該結點出現在棧頂,但是此時不能將其出棧並訪問,因此其右孩子還爲被訪問。所以接下來按照相同的規則對其右子樹進行相同的處理,當訪問完其右孩子時,該結點又出現在棧頂,此時可以將其出棧並訪問。這樣就保證了正確的訪問順序。可以看出,在這個過程中,每個結點都兩次出現在棧頂,只有在第二次出現在棧頂時,才能訪問它。因此需要多設置一個變量標識該結點是否是第一次出現在棧頂。                                                                     */
/************************************************************************/
void postOrderTraverse1(BiTree p){

	BiTNodeTag *stack[MAX_SIZE];
	int top = -1;
				
	while(top > -1 || p != NULL){
		while(p != NULL){
			BiTNodeTag *btn=(BiTNodeTag *)malloc(sizeof(BiTNodeTag));
			btn->btnode = p;
			btn->tag = 1;
			stack[++top]= btn;
			
			p = p->lchild;
		}
		if (top >-1){
			if (stack[top]->tag ==1 ){
				p = stack[top]->btnode;
				stack[top]->tag = 2;
				p = p->rchild;
			} else{
				p = stack[top--]->btnode;
				printNodeData(p);
				//因爲要退棧,所以這裏必須要置爲空
				p=NULL;
				
			}
		}
		
	}
		
}

void postOrderTraverse2(BiTree p){

	BiTNodeTag stack[MAX_SIZE];
	int top = -1;

	while(top > -1 || p != NULL){
		while(p != NULL){
			
			top++;
			stack[top].btnode = p;
			stack[top].tag = 1;
			
			p = p->lchild;
		}
		if (top >-1){
			if (stack[top].tag ==1 ){
				p = stack[top].btnode;
				stack[top].tag = 2;
				p = p->rchild;
			} else{
				p = stack[top--].btnode;
				printNodeData(p);
				//因爲要退棧,所以這裏必須要置爲空
				p=NULL;

			}
		}

	}
	
}
/************************************************************************/
/* 根據特點訪問。。。要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點P,先將其入棧。如果P不存在左孩子和右孩子,則可以直接訪問它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,則同樣可以直接訪問該結點。若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。                                                                     */
/************************************************************************/
void postOrderTraverse3(BiTree p){

	BiTNode *stack[MAX_SIZE];
	int top = -1;

	stack[++top] = p;//根節點入棧
	BiTNode * pre = NULL;	//用於記錄上次訪問結點

	BiTNode * cur = NULL;

	while(top >-1){
		cur = stack[top];
		if ((cur->lchild == NULL && cur->rchild == NULL )||(pre!= NULL &&(pre == cur->rchild || pre == cur->lchild))){
			printNodeData(cur);
			//訪問過之後,將這個結點移除
			top--;
			pre = cur;
		} else {
			if(cur->rchild != NULL){

				stack[++top] = cur->rchild;    
			}  
			if(cur->lchild != NULL){

				stack[++top] = cur->lchild;    
			}  
		}
	}

}
//非遞歸後序遍歷。。 最優方法 
void postOrderTraverse4(BiTree p){
	BiTNode *stack[MAX_SIZE];
	int top = -1;

	stack[++top] = p;
	p = p->lchild;
	BiTNode *pre = NULL;//之前的一個結點
	while (top > -1){
		//訪問左子樹
		while(p != NULL){
			stack[++top] = p;
			p = p->lchild;
		}
		//每次都要將其置爲空
		pre = NULL;
		
		//這裏使用while而不使用if的原因是,
		//如果使用if證明以下語句至多執行一次,而棧中有多個左子樹的結點已經訪問過。而其右子樹(多個結點)沒有訪問過。

		while (top>-1){
			p = stack[top];
			//因爲如果pre == p->rchild即前一個結點等於當前結點的右結點,證明,當前結點的左子樹已經輸出,而且其右子樹也已經輸出,則本結點可以輸出。
			//第一個輸出的是根節點
			if (pre == p->rchild){
				top--;
				printNodeData(p);
				pre = p;
			}else {
				//如果不是,則訪問右子樹。
				p = p->rchild;
				break;
			}


		}
	}

}


BiTNode *queue[MAX_SIZE];
int front= 0, rear = 0;
//遞歸層次遍歷,使用隊列
void levelOrderTraverse(BiTree p){

	if (p == NULL){
		return;
	}
	printNodeData(p);
	if ( p->lchild != NULL){
		queue[rear++] = p->lchild;
	}
	if ( p->rchild != NULL){
		queue[rear++] = p->rchild;
	}
	p = queue[front++];
	levelOrderTraverse(p);

}

void printDataByLevel(BiTNode *p, int i,int n);
int countLevelOfBiTree2(BiTree p);
//按照層次遍歷,不使用隊列
void levelOrderTraverse1(BiTree p){

	int level = countLevelOfBiTree2(p);
	int i = 1 ;
	for (i= 1;i<=level;i++){
		printDataByLevel(p,i,1);
	}

}
//按照層次打印
void printDataByLevel(BiTNode *p, int i,int n){
	if (p == NULL){
		return;
	}

	if (i == n){
		printNodeData(p);
	}

	printDataByLevel(p->lchild,i,n+1);
	printDataByLevel(p->rchild,i,n+1);

}

//非遞歸層次遍歷
void levelOrderTraverse2(BiTree p){

	BiTNode *queue[MAX_SIZE];
	int front= 0, rear = 0;

	queue[rear++] = p;

	while(front != rear){

		p = queue[front++];
		printNodeData(p);
		if ( p->lchild != NULL){
			queue[rear++] = p->lchild;
		}
		if ( p->rchild != NULL){
			queue[rear++] = p->rchild;
		}
		
	}

}

//遞歸求二叉樹高度
int countLevelOfBiTree1(BiTree p){
	if (p == NULL){
		return 0;
	}
	int lel = countLevelOfBiTree1(p->lchild);
	int ler = countLevelOfBiTree1(p->rchild);
	
	return lel > ler ? lel +1: ler+1;
}

//非遞歸求二叉樹的高度,在非遞歸層次遍歷基礎上修改
/************************************************************************/
/* 因爲訪問完一層之後,這一層所有結點的子節點也已經完全進入隊列。
 * 根據這個特點來計算二叉樹層次
 * 我們使用visitedNumber表示出棧的元素的下標,enQueNumber表示進棧元素的下標,lastNumberOfOneLevel表示一層當中最後一個元素的下標
 * 每次訪問結點時:visitedNumber+1,進棧時:enQueNumber+1,當一層所有的元素都出棧時lastNumberOfOneLevel=下一層最後一個元素的下標。
 * 
 */
/************************************************************************/
int countLevelOfBiTree2(BiTree p){

	BiTNode *queue[MAX_SIZE];
	int front= 0, rear = 0;
	queue[rear++] = p;

	int visitedNumber = 0;   
	int enQueNumber = 1; //當前入棧的序號,root爲1  
	int lastNumberOfOneLevel = 1;  //因爲已經有一個入隊列
	int height = 0;   

	while(front != rear){

		p = queue[front++];
		
		visitedNumber++;

		if ( p->lchild != NULL){
			queue[rear++] = p->lchild;
			enQueNumber++;
		}
		if ( p->rchild != NULL){
			queue[rear++] = p->rchild;
			enQueNumber++;
		}

		if (lastNumberOfOneLevel == visitedNumber){
			height ++;
			lastNumberOfOneLevel = enQueNumber;
		}


	}
	return height;


}
//求一點在樹的那層。非遞歸形式,
int getLevelOfOneNodeInBiTree(BiTree p,char item){

	BiTNode *queue[MAX_SIZE];
	int front= 0, rear = 0;
	queue[rear++] = p;

	int visitedNumber = 0;   
	int enQueNumber = 1; //當前入棧的序號,root爲1  
	int lastNumberOfOneLevel = 1;  //因爲已經有一個入隊列
	int height = 0;   

	while(front != rear){

		p = queue[front++];
		
		visitedNumber++;

		if ( p->lchild != NULL){
			queue[rear++] = p->lchild;
			enQueNumber++;
		}
		if ( p->rchild != NULL){
			queue[rear++] = p->rchild;
			enQueNumber++;
		}

		if (lastNumberOfOneLevel == visitedNumber){
			height ++;
			lastNumberOfOneLevel = enQueNumber;
		}
		if (item == p->data){
			if (lastNumberOfOneLevel < enQueNumber){
				return height + 1;
			} else {
				return height;
			}
			
		}

	}
	return -1;
}
//求一點在樹的那層。遞歸形式
void getLevelOfOneNodeInBiTree2(BiTree p,char item,int i,int *n){

	if (p == NULL){
		return;
	}
	if (item == p->data){
		*n = i;
	} else {
		getLevelOfOneNodeInBiTree2(p->lchild,item,i+1,n);
		getLevelOfOneNodeInBiTree2(p->rchild,item,i+1,n);
	}

}
//遞歸判斷兩棵二叉樹是否相似
int similarBiTree(BiTree p1,BiTree p2){
	if (p1 == NULL && p2 == NULL){
		return 1;
	} else if (p1 == NULL || p2 == NULL){
		return 0;
	} else {
		return(similarBiTree(p1->rchild,p2->rchild)*similarBiTree(p1->lchild,p2->lchild));
	}

}

/************************************************************************/
/*判斷一棵二叉樹是不是完全二叉樹。
 *分爲兩種情況:
 *一、二叉樹採用順序存儲方式,這種方式中,只從前向後判斷沒有空節點即可。
 *
 *二、樹採用鏈表形式進行存儲,這個時候,只要對二叉樹按層進行遍歷判斷:
 *
 *1、某結點沒有左孩子,則一定沒有右孩子。
 *2、某結點如果沒有左孩子或右孩子,那麼其後序結點一定沒有孩子。
*/
/************************************************************************/
int fullBiTree(BiTree p){

	BiTNode *queue[MAX_SIZE];
	int front= 0, rear = 0;

	queue[rear++] = p;
	int haveChild = 1;
	while(front != rear){

		p = queue[front++];
		

		if (p->lchild == NULL && p->rchild != NULL){
			return 0;
		}

		if (!haveChild && (p->lchild != NULL || p->rchild != NULL)){
			return 0;
		}

		if (p->lchild == NULL || p->rchild == NULL ){
			haveChild = 0;
		}
		
		if ( p->lchild != NULL){
			queue[rear++] = p->lchild;
		}
		if ( p->rchild != NULL){
			queue[rear++] = p->rchild;
		}

	}
	return 1;
}

//輸出根節點到P結點的路徑
//採用非遞歸後序形式判斷,當輸出元素與結點元相同時,棧中的所有元素就是路徑。
void printPath(BiTree p , char s){

	BiTNode *stack[MAX_SIZE];
	int top = -1;

	stack[++top] = p;
	p = p->lchild;

	BiTNode * pre=NULL;
	while (top >-1){
		while (p != NULL){
			stack[++top] = p;
			p = p->lchild;
		}
		pre = NULL;
		while (top>-1){
			p = stack[top];
			if (p ->rchild == pre){
				//找到這個結點了,將這時棧中的所有元素輸出。
				if(p->data == s){
					
					while(top>-1){
						printNodeData(stack[top--]);
					}
					break;
				}

				top--;
				pre = p;
			} else {
				p= p->rchild;
				break;
			}
		}
	}

}
//得到兩個結點的最近的共同祖先
/************************************************************************/
/* 
   採用非遞歸後序形式判斷,當輸出元素與結點元相同時,棧中的所有元素就是該元素的路徑。
   設置一個對每個結點設置一個標誌位,標識是否是一個元素的祖先結點,當是祖先結點時,
   將該標誌位設置爲1,當第二個元素再次訪問該標誌位時如果是0,則將其設置爲1,如果爲1
   表示,當前結點是另外一個節點的祖先結點,因此將其輸出即可。
   注意:遍歷棧中的元素時採用從棧頂到棧尾的方式遍歷。
*/
/************************************************************************/

char getAncestorOfTwoNode(BiTree p,char p1,char p2){
	BiTNodeTag stack[MAX_SIZE];
	int top = -1;

	top++;
	stack[top].btnode = p;
	stack[top].tag = 0;

	p = p->lchild;

	BiTNode * pre = NULL;

	int i = 0;
	while(top > -1){
		while(p != NULL){
			top++;
			stack[top].btnode = p;
			stack[top].tag = 0;

			p = p->lchild;
		}
		pre = NULL;

		while(top > -1){
			p = stack[top].btnode;
			//判斷是否是第二次入棧
			if (pre == p ->rchild){
				//printNodeData(p);

				if (p->data == p1 || p->data == p2){
					for (i = top;i >= 0;i--){
						if (stack[i].tag == 0){
							stack[i].tag = 1;
						} else {
							return (stack[i].btnode)->data;
						}
					}
				}

				top--;
				pre = p;
			} else {
				p = p->rchild;
				break;
			}

		}

	}
	return '-';

}

//拆分二叉樹,輸入一個節點值,將以這個值爲根節點的樹分爲兩個樹。
BiTNode* disLink(BiTNode **p,char data){

	BiTNode *stack[MAX_SIZE];
	int top = -1;
	BiTNode *t = NULL;
	while (top > -1 || *p != NULL){
		
		if (p != NULL){
			//printNodeData(*p);
			if (data == (*p)->data){
				t = *p;
				p = NULL;
				break;
			}
			stack[++top] = *p;
			*p = (*p)->lchild;
		} else {
			*p = stack[top--];
			*p = (*p)->rchild;
		}

	}

	return t;

}
//統計二叉樹的結點個數。遍歷二叉樹即可
int countNodes(BiTree p){

	BiTNode *stack[MAX_SIZE];
	int top = -1;
	int count = 0;
	while(p != NULL || top>-1){
		
		while(p != NULL){
			stack[++top] = p;
			p = p->lchild;
		}
		if (top>-1){
			p = stack[top--];
		//	printNodeData(p);
			count++;
			p=p->rchild;
		}
	}
	return count;
	
}
/*******************************線索二叉樹相關操作開始********************************************/
//創建中序的線索二叉樹,對其進行線索化。
BiThrNode * inOrderTreading(BiThrNode *p){

	BiThrNode* stack[MAX_SIZE];
	int top = -1;
	BiThrNode* pre = NULL;
	BiThrNode *root = p;
	while(top > -1 || p != NULL){

		while (p != NULL){
			stack[++top] = p;
			p = p ->lchild;
		}

		if (top > -1){
			p = stack[top--];

			//證明這是第一個結點
			if (pre == NULL){
				p->lchild = NULL;
			}else{
				//建立後記線索
				if (pre ->rchild == NULL){
					pre ->rtag = 1;
					pre->rchild = p;
				}
				//建立前驅線索
				if (p->lchild == NULL){
					p ->lchild = pre;
					p->ltag = 1;
				}
			}
			//設置前前一個結點。
			pre = p;
			//printf("%c",p->data);
			p = p->rchild;

		} else {
			break;
		}

	}
	
	return root;
}
//申請一個線索二叉樹結點
BiThrNode * mallocBiThrNode(char s){

	BiThrNode *root = (BiThrNode *)malloc(sizeof(BiThrNode));
	root->data = s;
	root->lchild = NULL;
	root->rchild = NULL;
	root->ltag = 0;
	root->rtag = 0;
	return root;
}
//構建線索二叉樹
BiThrNode * createThrTree(){
	char str[] ="ABC@G@@@DE@@@";
	char *ps = str;

	BiThrNode *stack[MAX_SIZE];
	int top = -1;

	if (*ps == '@'){
		printf("空線索二叉樹");
		exit(0);
	}
	BiThrNode *root = mallocBiThrNode(*ps);
	ps++;
	stack[++top] = root;
	BiThrNode *p = root;
	
	BiThrNode *temp ;
	int rl = 1;

	while(*ps != '\0'){
		if (*ps != '@'){

			if (rl == 1){
				temp = mallocBiThrNode(*ps);
				p->lchild = temp;
				p = temp;
				stack[++top] = p;
				

			} else {
				temp = mallocBiThrNode(*ps);
				p->rchild = temp;
				p = temp;
				stack[++top] = p;

				rl = 1;
			}

		} else {

			if (rl == 1){
				rl = 2;
			}


			if (top > -1){
				p = stack[top--];
			} else {
				break;
			}


		}
		ps++;
	}
	
	return root;
}
//找到某個結點的後繼結點
BiThrNode * succ(BiThrNode * p){

	if (p->rtag == 1){
		return p->rchild;
	} else {
		//中序遍歷特點LDR,後繼結點當前結點處於D處,因爲已經訪問到當前結點了。
		//所以需要從右子樹找後繼結點,從LDR的特點來看,這個結點就是右子樹的最左側的那個節點。
		
		//爲什麼要使用ltag呢,因爲,所有的lchild屬性都已經使用了。
		if ((p = p->rchild)!= NULL){
		while(p->ltag == 0){
			p = p->lchild;
		}
		}
		
		return p;
	}

}
//找到某個樹的前驅結點
BiThrNode * pre(BiThrNode *p){

	if (p->ltag == 1){
		return p->lchild;
	} else {
		//中序遍歷特點LDR,後繼結點當前結點處於D處,因爲已經訪問到當前結點了。
		//所以需要從左子樹找前驅結點,從LDR的特點來看,這個結點就是左子樹的最右側的那個節點。
		
		
		//p = p->lchild;
		if ((p = p->lchild) != NULL){
			while(p->rtag == 0){
				p = p->rchild;
			}
		}
		return p;
	}

}
//非遞歸輸出中序遍歷線索二叉樹
void inOrderTraverseThrTree(BiThrNode * p){
	
	BiThrNode * temp;
	//LDR中序遍歷,先找前序結點
	while(p != NULL){
		temp = p;
		p = pre(p);
	}
	p = temp;
	while(p != NULL){
		printf("%c",p->data);
		p = succ(p);
	}

}

/*******************************線索二叉樹相關操作結束********************************************/

typedef struct BiTreeNode{
	//保存原始值
	char s;
	//是否訪問過
	int flag;
	//
	BiTNode *p;

}BiTreeNode;
int getPositionOfNode(char s, BiTreeNode *nodes,int len);
int getPostionBetweenPos1AndPos2(int pos1, int pos2,BiTreeNode *nodes);

//由前序和中序序列得到二叉樹,非遞歸
//實際上,只要將後序序列,前後調換順序,得到的二叉樹是一樣的。因此,後序就不再寫了。
BiTNode * getBiTreeByPreAndIn(char * p1,char *p2){

	int len = strlen(p2);
	BiTreeNode *nodes = new BiTreeNode[len];
	int i = 0;
	//初始化
	for (i = 0;i < len ;i++){

		nodes[i].s = *(p2+i);
		nodes[i].flag = 0;

		nodes[i].p = (BiTNode *)malloc(sizeof(BiTNode));
		nodes[i].p->data = *(p2+i);
		nodes[i].p->lchild = NULL;
		nodes[i].p->rchild = NULL;
	}

	BiTNode *root = NULL;
	//後序和中序時,讀出後序的最後一個在中序中找到並標識
	for (i = 0;i<len;i++){
		//將根節點設置爲已讀
		if (nodes[i].p->data == *p1){
			nodes[i].flag = 1;
			root = nodes[i].p;
		}
	}
	//後序時,只要將其i從大往小遞減即可
	for (i = 0;i<len-1;i++){
		int pos1 = getPositionOfNode(p1[i],nodes,len);
		int pos2 = getPositionOfNode(p1[i+1],nodes,len);

		int pos3 = getPostionBetweenPos1AndPos2(pos1,pos2,nodes);

		//設置爲已讀
		nodes[pos2].flag = 1;

		if (pos3 > pos2){
			nodes[pos3].p->lchild = nodes[pos2].p;
		} else {
			nodes[pos3].p->rchild = nodes[pos2].p;
		}

	}

	return root;
}

int getPositionOfNode(char s, BiTreeNode *nodes,int len){
	int i = 0;
	for (i = 0;i<len;i++){
		if (s == nodes[i].s){
			return i;
		}
	}
}
int getPostionBetweenPos1AndPos2(int pos1, int pos2,BiTreeNode *nodes){
	int i = 0;
	//得到pos1和pos2之間離pos2最近的已經訪問過的那個結點的位置。
	if (pos1 > pos2){
		for (i=pos2;i<=pos1;i++){

			if (nodes[i].flag ==1){
				return i;
			}
		}
	} else {
		for (i = pos2;i>=pos1;i--){
			if (nodes[i].flag ==1){
				return i;
			}
		}
	}

}



//由前序和中序序列得到二叉樹,遞歸
BiTNode * getBiTreeByPreAndIn2(char * ppos,char *ipos,int n){
	BiTNode *ptr;
	char *rpos;
	int k;
	if (n <= 0){
		return NULL;
	}
	ptr = (BiTNode*)malloc(sizeof(BiTNode));
	ptr->data = *ppos;

	for (rpos = ipos;rpos <ipos+n;rpos++){
		if (*rpos == *ppos){
			break;
		}
	}
	//根結點的位置
	k = rpos -ipos;
	ptr->lchild = getBiTreeByPreAndIn2(ppos+1,ipos,k);
	ptr->rchild = getBiTreeByPreAndIn2(ppos+1+k,rpos+1,n-1-k);

	return ptr;
}


void main(){

	BiTNode * root = createBiTree();
	printf("前序遍歷:\n");
	preOrderTraverse(root);
	printf("\n");
	preOrderTraverse1(root);
	printf("\n");
	preOrderTraverse2(root);
	printf("\n");
	preOrderTraverse3(root);
	
	printf("\n\n");
	printf("中序遍歷:\n");
	inOrderTraverse(root);
	printf("\n");
	inOrderTraverse1(root);
	
	printf("\n\n");
	printf("後序遍歷:\n");
	postOrderTraverse(root);
	printf("\n");
	postOrderTraverse1(root);
	printf("\n");
	postOrderTraverse2(root);
	printf("\n");
	postOrderTraverse3(root);
	printf("\n");
	postOrderTraverse4(root);
	
	printf("\n\n");
	printf("層次遍歷:\n");
	levelOrderTraverse(root);
	printf("\n");
	levelOrderTraverse1(root);
	printf("\n");
	levelOrderTraverse2(root);
	printf("\n\n");
	printf("二叉樹的高度:\n");
	printf("the level is %d\n",countLevelOfBiTree1(root));
	printf("the level is %d\n",countLevelOfBiTree2(root));
	printf("\n");
	printf("查找某點在二叉樹的那一層:\n");
	printf("the level of %c in BiTree is %d\n",'E',getLevelOfOneNodeInBiTree(root,'E'));
	int i = 0;
	getLevelOfOneNodeInBiTree2(root,'E',1,&i);
	printf("the level of %c in BiTree is %d",'E',i);
	printf("\n\n");
	printf("判斷兩棵二叉樹是否相似:\n");
	printf("%d",similarBiTree(createBiTree(),createBiTree()));
	printf("\n\n");
	printf("判斷二叉樹是不是完全二叉樹:\n");
	printf("the tree is full tree %d",fullBiTree(root));
	printf("\n\n");
	printf("輸出某一結點的到跟結點的路徑:\n");
	printf("The path of the itme is ");
	printPath(root,'D');
	printf("\n\n");
	printf("得到兩個結點的最近的共同祖先: \n");
	printf("The common item is %c",getAncestorOfTwoNode(root,'C','G'));
	printf("\n\n");
	//printf("拆分二叉樹: \n");
	//preOrderTraverse(disLink(&root,'B'));
	//printf("\n");
	////指針沒掌握好,沒調試出來。
	//preOrderTraverse(root);
	//printf("\n\n");
	printf("統計二叉樹的結點個數:\n");
	printf("The count of the BinTree is %d",countNodes(root));
	printf("\n\n");

	printf("線索中序二叉樹的建立和輸出:\n");
	BiThrNode *thRoot = inOrderTreading(createThrTree());
	inOrderTraverseThrTree(thRoot);
	printf("\n\n");
	printf("根據前序和中序建立二叉樹:\n");
	postOrderTraverse4(getBiTreeByPreAndIn("abdgcefhi","dgbaechif"));
	printf("\n");
	postOrderTraverse4(getBiTreeByPreAndIn2("abdgcefhi","dgbaechif",9));
	printf("\n");
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章