二叉树表示法 P127页 /* typedef struct BiTNode { int data; struct BiTNode *lchild, *rchild; }BiTNode, *BiTree; */ struct BiTNode { int data; struct BiTNode *lchild, *rchild; }; typedef struct BiTNode BiTNode; typedef struct BiTNode * BiTree; 树的三叉链表表示
//三叉链表 typedef struct TriTNode { int data; //左右孩子指针 struct TriTNode *lchild, *rchild; struct TriTNode *parent; }TriTNode, *TriTree; 双亲链表法 //双亲链表 #define MAX_TREE_SIZE 100 typedef struct BPTNode { int data; int parentPosition; //指向双亲的指针 //数组下标 char LRTag; //左右孩子标志域 }BPTNode; typedef struct BPTree { BPTNode nodes[100]; //因为节点之间是分散的,需要把节点存储到数组中 int num_node; //节点数目 int root; //根结点的位置 //注意此域存储的是父亲节点在数组的下标 }BPTree; //用这个数据结构能表达出一颗树,为什么? 4.4.3二叉树的遍历
二叉树编程实践 基本操作 typedef struct node{ int data; struct node *lchild,*rchild; } NODE; NODE *root; DLR(NODE *root ) { if (root) //非空二叉树 { printf(“%d”,root->data); //访问D DLR(root->lchild); //递归遍历左子树 DLR(root->rchild); //递归遍历右子树 } } 中序遍历算法 LDR(NODE *root) { if(root !=NULL) { LDR(root->lchild); printf(“%d”,root->data); LDR(root->rchild); } } 后序遍历算法 LRD (NODE *root) {if(root !=NULL) {LRD(root->lchild); LRD(root->rchild); printf(“%d”,root->data); } }
计算二叉树中叶子结点的数目 int sum = 0; //全局变量 DLR_CountLeafNum(NODE *root)//采用中序遍历的递归算法 { if ( root) //非空二叉树条件,还可写成if(root !=NULL ) { if(!root->lchild&&!root->rchild) //是叶子结点则统计并打印 { sum++; printf("%d\n",root->data); } DLR_CountLeafNum(root->lchild); //递归遍历左子树,直到叶子处; DLR_CountLeafNum(root->rchild);}//递归遍历右子树,直到叶子处; } return(0); } 思想: 1)求根结点左子树的叶子结点个数,累计到sum中,求根结点右子树的叶子结点个数累计到sum中。 2)若左子树还是树,重复步骤1;若右子树还是树,重复步骤1。 3)全局变量转成函数参数 4)按照先序、中序、后序方式计算叶子结点, ===》三种遍历的本质思想强化:访问结点的路径都是一样的,计算结点的时机不同。
求二叉树的深度 思想: 1)求根结点左子树高度,根结点右子树高度,比较的子树最大高度,再+1。 2)若左子树还是树,重复步骤1;若右子树还是树,重复步骤1。
完全Copy二叉树 思想: 1)malloc新结点, 2)拷贝左子树,拷贝右子树,让新结点连接左子树,右子树 3)若左子树还是树,重复步骤1、2;若右子树还是树,重复步骤1、2。
树的非递归遍历(中序遍历)
中序 遍历的几种情况
分析1:什么时候访问根、什么时候访问左子树、什么访问右子树
当左子树为空或者左子树已经访问完毕以后,再访问根
访问完毕根以后,再访问右子树。
分析2:非递归遍历树,访问结点时,为什么是栈,而不是其他模型(比如说是队列)。
先走到的后访问、后走到的先访问,显然是栈结构
分析3:结点所有路径情况
步骤1:
如果结点有左子树,该结点入栈;
如果结点没有左子树,访问该结点;
步骤2:
如果结点有右子树,重复步骤1;
如果结点没有右子树(结点访问完毕),根据栈顶指示回退,访问栈顶元素,并访问右子树,重复步骤1
如果栈为空,表示遍历结束。
注意:入栈的结点表示,本身没有被访问过,同时右子树也没有被访问过。
分析4:有一个一直往左走入栈的操作,中序遍历的起点
3、#号法编程实践 利用前序遍历来建树(结点值陆续从键盘输入,用DLR为宜) Bintree createBTpre( ) { Bintree T; char ch; scanf(“%c”,&ch); if(ch==’#’) T=NULL; else { T=( Bintree )malloc(sizeof(BinTNode)); T->data=ch; T->lchild=createBTpre(); T->rchild=createBTpre(); } return T; } //后序遍历销毁一个树 void BiTree_Free(BiTNode* T) { BiTNode *tmp = NULL; if (T!= NULL) { if (T->rchild != NULL) BiTree_Free(T->rchild); if (T->lchild != NULL) BiTree_Free(T->lchild); if (T != NULL) { free(T); T = NULL; } } }