总结数据结构中树的重要基础知识:
1、二叉树
1.1 二叉树的表示形式
1.1.1 数组形式
根据二叉树的性质安排树中节点在数组中的位置,从根节点开始,对树中节点顺序编号,如1,2,3,...对一个具有n个节点的二叉树,采用数组表示时,具有下列两条性质:
(前提条件:根节点的数组下标为1)
性质a:对于节点i,如果2i<=n,则其左孩子节点在数组中位置为2i;如果2i>n,则该节点无左孩子。
性质b:对于节点i,如果2i+1<=n,则其右孩子节点在数组中位置为2i+1;如果2i+1>n,则该节点无右孩子。
C语言定义:
1 #define MAXSIZE 100 2 int treeArray[MAXSIZE]; //假设节点数据为int型
1.1.2 链表形式
二叉树具有多种链表形式,根据链表节点中指针域的不同,分为X叉链表,以下是树的链表节点的几种类型:
Type1:普通的二叉链表,节点包括数据域、指向左子树和右子树的指针,如下所示:
1 struct treeNode{ 2 int data; 3 struct treeNode * lchild; 4 struct treeNode * rchild; 5 };
Type2: 三叉链表,除了Type1中各子结构外,还有指向父节点的指针,如下所示:
1 struct treeNode{ 2 int data; 3 struct treeNode * lchild; 4 struct treeNode * rchild; 5 struct treeNode * parent; 6 };
Type3:线索链表,用于解决链表节点中指针浪费的问题,待补充:
1.2 建立一棵二叉树(采用先序递归建立)
输入为0表示该节点的左子节点或右子节点为空,可能的输入形式为:4 5 0 0 0 ,构造了一棵两个节点的树,其中data为5的节点为data为4的节点的左子节点,程序如下:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<assert.h> 4 5 //定义树节点 6 typedef struct treeNode{ 7 int data; 8 struct treeNode * lchild; 9 struct treeNode *rchild; 10 } *treeNodeP; 11 12 #define MALLOC(p) if(!(p = (treeNodeP)malloc(sizeof(struct treeNode)))) assert(p!=NULL); 13 14 bool createBiTree(treeNodeP *root); 15 void traverseBiTree(treeNodeP root); 16 17 //main函数 18 int main() 19 { 20 treeNodeP root; 21 createBiTree(&root); //注意:传递的是指针的指针 22 if(!root) 23 { 24 printf("root is null\n"); 25 exit(1); 26 } 27 printf("The root's lchild is: %d\n",root->lchild->data); 28 int temp; 29 temp = getchar(); 30 return 0; 31 } 32 //按先序次序建立二叉树 33 bool createBiTree(treeNodeP *p) 34 { 35 int d; 36 scanf("%d",&d); 37 if(d == 0) 38 *p = NULL; 39 else 40 { 41 MALLOC(*p); 42 (*p)->data = d; 43 createBiTree(&((*p)->lchild)); 44 createBiTree(&((*p)->rchild)); 45 } 46 return true; 47 }
1.3 遍历二叉树
1.3.1 递归遍历
二叉树的递归遍历有三种类型:前序遍历、中序遍历、后序遍历,具体实现如下:
1 //1. 递归先序遍历 2 void rePreTraBiTree(treeNodeP root) 3 { 4 if(!root) 5 return; 6 else 7 { 8 printf("Tree: %d\n",root->data); 9 rePreTraBiTree(root->lchild); 10 rePreTraBiTree(root->rchild); 11 } 12 } 13 //2. 递归中序遍历 14 void reInTraBiTree(treeNodeP root) 15 { 16 if(!root) 17 return; 18 else 19 { 20 reInTraBiTree(root->lchild); 21 printf("Tree: %d\n",root->data); 22 reInTraBiTree(root->rchild); 23 } 24 } 25 //3. 递归后序遍历 26 void rePosTraBiTree(treeNodeP root) 27 { 28 if(!root) 29 return; 30 else 31 { 32 rePosTraBiTree(root->lchild); 33 rePosTraBiTree(root->rchild); 34 printf("Tree: %d\n",root->data); 35 } 36 }
1.3.2 非递归遍历
二叉树的递归遍历函数调用次数较多,效率较低,每种递归遍历均有相应的非递归遍历算法,二叉树前序、中序和后序的非递归遍历实现如下:
1 //4. 非递归先序遍历 2 void nonrePreTraBiTree(treeNodeP root) 3 { 4 stackNodeP stack; 5 //treeNodeP ttemp; 6 stack = stackCreate(); 7 while(1) 8 { 9 for(;root;root = root->lchild) 10 { 11 printf("Tree: %d\n",root->data); 12 push_stack(root, &stack); 13 } 14 root = pop_stack(&stack); 15 if(root == NULL) 16 break; 17 root = root->rchild; 18 } 19 } 20 //5. 非递归中序遍历 21 void nonreInTraBiTree(treeNodeP root) 22 { 23 stackNodeP stack; 24 //treeNodeP ttemp; 25 stack = stackCreate(); 26 while(1) 27 { 28 for(;root;root = root->lchild) 29 push_stack(root, &stack); 30 root = pop_stack(&stack); 31 if(root == NULL) 32 break; 33 printf("Tree: %d\n",root->data); 34 root = root->rchild; 35 } 36 } 37 //6. 非递归后序遍历 38 void nonrePosTraBiTree(treeNodeP root) 39 { 40 stackNodeP stack; 41 treeNodeP ttemp; 42 stack = stackCreate(); 43 //第一棵左子树入栈到底 44 for(;root;root = root->lchild) 45 { 46 root->flag = 0; 47 push_stack(root,&stack); 48 } 49 while(1) 50 { 51 ttemp = pop_stack(&stack); 52 if(ttemp == NULL) 53 break; 54 while(ttemp->rchild != NULL && ttemp->flag == 0) 55 { 56 ttemp->flag =1; 57 push_stack(ttemp, &stack); //重新入栈 58 ttemp = ttemp->rchild; 59 for(;ttemp;ttemp = ttemp->lchild) 60 { 61 ttemp->flag =0; 62 push_stack(ttemp, &stack); 63 } 64 ttemp = pop_stack(&stack); 65 } 66 printf("tree: %d\n",ttemp->data); 67 } 68 }
1.4 完整程序
1 /* 2 * Created By Chunxin Yang, NWPU. 3 */ 4 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<assert.h> 8 9 //定义树节点 10 typedef struct treeNode{ 11 int data; 12 struct treeNode * lchild; 13 struct treeNode *rchild; 14 int flag; //标识后序遍历每个节点的右子树是否访问过 15 } *treeNodeP; 16 //定义栈节点 17 typedef struct stackNode{ 18 treeNodeP tp; 19 struct stackNode * next; 20 } *stackNodeP; 21 22 #define MALLOC(p) if(!(p = (treeNodeP)malloc(sizeof(struct treeNode)))) assert(p!=NULL); 23 24 bool createBiTree(treeNodeP *root); 25 void traverseBiTree(treeNodeP root); 26 27 stackNodeP stackCreate(); 28 void push_stack(treeNodeP root, stackNodeP *top); 29 treeNodeP pop_stack(stackNodeP *top); 30 31 void rePreTraBiTree(treeNodeP root); //递归先序 32 void reInTraBiTree(treeNodeP root); //递归中序 33 void rePosTraBiTree(treeNodeP root); //递归后序 34 void nonrePreTraBiTree(treeNodeP root); //非递归先序 35 void nonreInTraBiTree(treeNodeP root); //非递归中序 36 void nonrePosTraBiTree(treeNodeP root); //非递归后序 37 38 //main函数 39 int main() 40 { 41 treeNodeP root; 42 createBiTree(&root); //注意:传递的是指针的指针 43 if(!root) 44 { 45 printf("root is null\n"); 46 exit(1); 47 } 48 //printf("The root's lchild is: %d\n",root->lchild->data); 49 traverseBiTree(root); 50 int temp; 51 temp = getchar(); 52 getchar(); 53 getchar(); 54 return 0; 55 } 56 //按先序次序建立二叉树 57 bool createBiTree(treeNodeP *p) 58 { 59 int d; 60 scanf("%d",&d); 61 if(d == 0) 62 *p = NULL; 63 else 64 { 65 MALLOC(*p); 66 (*p)->data = d; 67 createBiTree(&((*p)->lchild)); 68 createBiTree(&((*p)->rchild)); 69 } 70 return true; 71 } 72 //遍历二叉树 73 void traverseBiTree(treeNodeP root) 74 { 75 //1. 递归先序遍历 76 printf("1:先序遍历\n"); 77 rePreTraBiTree(root); 78 //2. 递归中序遍历 79 printf("2:中序遍历\n"); 80 reInTraBiTree(root); 81 //3. 递归后序遍历 82 printf("3:后序遍历\n"); 83 rePosTraBiTree(root); 84 //4. 非递归先序遍历 85 printf("4:非递归先序遍历\n"); 86 nonrePreTraBiTree(root); 87 //5. 非递归中序遍历 88 printf("5:非递归中序遍历\n"); 89 nonreInTraBiTree(root); 90 //6. 非递归后序遍历 91 printf("6:非递归后序遍历\n"); 92 nonrePosTraBiTree(root); 93 } 94 //1. 递归先序遍历 95 void rePreTraBiTree(treeNodeP root) 96 { 97 if(!root) 98 return; 99 else 100 { 101 printf("Tree: %d\n",root->data); 102 rePreTraBiTree(root->lchild); 103 rePreTraBiTree(root->rchild); 104 } 105 } 106 //2. 递归中序遍历 107 void reInTraBiTree(treeNodeP root) 108 { 109 if(!root) 110 return; 111 else 112 { 113 reInTraBiTree(root->lchild); 114 printf("Tree: %d\n",root->data); 115 reInTraBiTree(root->rchild); 116 } 117 } 118 //3. 递归后序遍历 119 void rePosTraBiTree(treeNodeP root) 120 { 121 if(!root) 122 return; 123 else 124 { 125 rePosTraBiTree(root->lchild); 126 rePosTraBiTree(root->rchild); 127 printf("Tree: %d\n",root->data); 128 } 129 } 130 //4. 非递归先序遍历 131 void nonrePreTraBiTree(treeNodeP root) 132 { 133 stackNodeP stack; 134 //treeNodeP ttemp; 135 stack = stackCreate(); 136 while(1) 137 { 138 for(;root;root = root->lchild) 139 { 140 printf("Tree: %d\n",root->data); 141 push_stack(root, &stack); 142 } 143 root = pop_stack(&stack); 144 if(root == NULL) 145 break; 146 root = root->rchild; 147 } 148 } 149 //5. 非递归中序遍历 150 void nonreInTraBiTree(treeNodeP root) 151 { 152 stackNodeP stack; 153 //treeNodeP ttemp; 154 stack = stackCreate(); 155 while(1) 156 { 157 for(;root;root = root->lchild) 158 push_stack(root, &stack); 159 root = pop_stack(&stack); 160 if(root == NULL) 161 break; 162 printf("Tree: %d\n",root->data); 163 root = root->rchild; 164 } 165 } 166 //6. 非递归后序遍历 167 void nonrePosTraBiTree(treeNodeP root) 168 { 169 stackNodeP stack; 170 treeNodeP ttemp; 171 stack = stackCreate(); 172 //第一棵左子树入栈到底 173 for(;root;root = root->lchild) 174 { 175 root->flag = 0; 176 push_stack(root,&stack); 177 } 178 while(1) 179 { 180 ttemp = pop_stack(&stack); 181 if(ttemp == NULL) 182 break; 183 while(ttemp->rchild != NULL && ttemp->flag == 0) 184 { 185 ttemp->flag =1; 186 push_stack(ttemp, &stack); //重新入栈 187 ttemp = ttemp->rchild; 188 for(;ttemp;ttemp = ttemp->lchild) 189 { 190 ttemp->flag =0; 191 push_stack(ttemp, &stack); 192 } 193 ttemp = pop_stack(&stack); 194 } 195 printf("tree: %d\n",ttemp->data); 196 } 197 } 198 //建栈 199 stackNodeP stackCreate() 200 { 201 stackNodeP top = NULL; 202 return top; 203 } 204 //如栈 205 void push_stack(treeNodeP root, stackNodeP *top) 206 { 207 stackNodeP temp; 208 if(top == NULL) 209 { 210 if(!((*top) = (stackNodeP)malloc(sizeof(stackNode)))) assert((*top)!=NULL); 211 (*top)->tp = root; 212 (*top)->next = NULL; 213 }else{ 214 if(!(temp = (stackNodeP)malloc(sizeof(stackNode)))) assert(temp!=NULL); 215 temp->tp = root; 216 temp->next = *top; 217 *top = temp; 218 } 219 } 220 //出栈 221 treeNodeP pop_stack(stackNodeP *top) 222 { 223 treeNodeP temp; 224 if((*top) == NULL) 225 return NULL; 226 temp = (*top)->tp; 227 (*top) = (*top)->next; 228 return temp; 229 }