樹是遞歸定義的,利用遞歸算法遍歷樹實現起來比較簡單,然而難的是非遞歸遍歷。非遞歸遍歷需要藉助棧這一數據結構來完成。
首先定義樹的結點和構建鏈表棧:
//定義樹的節點 typedef struct Node { int data; struct Node* lchild; struct Node* rchild; }Node; //定義棧節點 typedef struct Stacknode { Node* tnode; struct Stacknode* next; }Stacknode; //構建棧 typedef struct Stacktree { struct Stacknode* top; }Stacktree; //初始化棧 void init_stack(Stacktree* T) { T->top=NULL; } //判斷棧是否爲空 int is_stack_empty(Stacktree* T) { if(T->top==NULL) return 1; return 0; } //獲取棧頂值 Node* get_stack_topvalue(Stacktree* T) { if(is_stack_empty(T)) { return (Node*)-1; } return T->top->tnode; } //進棧 void Push(Stacktree* T,Node* value) { if(T==NULL) { return ; } Stacknode* newnode=(Stacknode*)malloc(1*sizeof(Stacknode)); newnode->tnode=value; newnode->next=T->top; T->top=newnode; } //出棧 void Pop(Stacktree* T) { if(is_stack_empty(T)) { return ; } Stacknode* tmp=T->top; T->top=T->top->next; free(tmp); tmp=NULL; }
創建樹:
Node* create_tree() { int _data; scanf("%d",&_data); if(_data==-1) { return NULL; } Node* root=(Node*)malloc(1*sizeof(Node)); root->data=_data; root->lchild=create_tree(); root->rchild=create_tree(); return root; }
遍歷:
1.非遞歸前序遍歷:
思想:(1)訪問結點p,並將節點p進棧。如p的左孩子不爲空,這將p的左孩子置爲結點p,重複(1);若p的左孩子爲空,這獲取棧頂值並出棧,棧頂結點的右孩子賦給p,重複(1),如棧爲空且p==NULL,則遍歷結束。
void pre_print(Node* root) { if(root) { Stacktree st; init_stack(&st); while(root!=NULL || !is_stack_empty(&st)) { while(root!=NULL) { printf("%d\t",root->data); Push(&st,root); root=root->lchild; } if(!is_stack_empty(&st)) { root=get_stack_topvalue(&st); Pop(&st); root=root->rchild; } } printf("\n"); } }
2.非遞歸中序遍歷:
思想:
對於任意結點p
(1)若左孩子不爲空,則將p進棧並將p的左孩子置爲當前的p,然後對當前結點p進行同樣處理。
(2)若左孩子爲空,這訪問該結點,並將棧頂元素出棧且將p置爲棧頂元素的右孩子,進行(1)操作。
(3)知道p爲空且棧頂元素爲空時遍歷結束。
void mid_print(Node* root) { if(root) { Stacktree st; init_stack(&st); while(root!=NULL || !is_stack_empty(&st)) { while(root!=NULL) { Push(&st,root); root=root->lchild; } if(!is_stack_empty(&st)) { root=get_stack_topvalue(&st); Pop(&st); printf("%d\t",root->data); root=root->rchild; } } } }