树
空树和非空树
树是一个递归的定义,根结点除外剩余的部分都可以看作为一棵树。
子树之间是互不相交的
内部节点:除了树根和子叶节点
树根是第一层(不统一,不同书的描述不同。)
树的存储
- 顺序存储
- 双亲表示法 优点:找双亲方便 缺点:找孩子不容易
- 孩子表示法 优点:找孩子方便 缺点:树的节点最大度 为开辟的空间,很浪费空间。 找双亲不方便
- 双亲孩子表示法 优点:找孩子和双亲方便 缺点:耗费空间
- 链式存储
- 孩子链表表示法 把孩子放在头节点后面 类似于链式前向星表示
- 孩子兄弟表示法 左指针长子 右指针兄弟 根据孩子兄弟表示法把任何树都可以转化为二叉树(相互转化)
森林把每颗树树根看成兄弟
二叉树
用处比较多
每一层是上一层的2倍
任何一颗二叉树,叶子节点数为n0,度数为2的节点为n2,n0=n2+1
n=n0+n1+n2总节点数,节点数等于分支数加一;n=1*n1+2*n2+1;
1*n1+2*n2+1 = n0+n1+n2 故,得到n0=n2+1
二叉树存储
- 顺序存储:
- 补零补成完全二叉树,然后句可以按顺序存储。 缺点 补零可能太多。
- 完全二叉树 可以 顺序存储
- 用 l[]数组 和 r[]数组 必须指明根root节点 经常用
- 链式存储:
- lchild data rchild
二叉树遍历
先序遍历:根左右 递归
中序遍历:左根右 递归
后序遍历:左右根 递归
层次遍历:一层一层访问(同一层从左向右) 方法:队列 出队的同时孩子进去
已知先序和中序、后序和中序要得到另外一个序列其实拆解都是中序序列。
空就结束,不操作。
题目一:补空创建二叉树
输入:补空序列 创建二叉树
1 #include <iostream> 2 #include <queue> 3 4 using namespace std; 5 6 // 定义二叉树存储结构 7 struct Bonde{ 8 char data; 9 struct Bonde *lchild, *rchild; 10 }; 11 typedef struct Bonde *Btree; 12 typedef struct Bonde Bonde; // 给看结构体起的别名 13 14 // 创建二叉树函数 15 void Createtree(Btree &T) 16 { 17 // 按先序次序输入二叉树中结点的值(一个字符,创建二叉链表表示的二叉树T) 18 char ch; 19 cin >> ch; 20 if(ch == '#') 21 T = NULL; //递归结束,建空树 22 else{ 23 T = new Bonde; 24 T->data = ch; // 生成根结点 25 Createtree(T->lchild); // 递归创建做子树 26 Createtree(T->rchild); // 递归创建右子树 27 } 28 } 29 30 int Depth(Btree T){ // 求二叉树的深度 31 int m, n; 32 if(T == NULL) // 如果为空树,c深度为0 33 return 0; 34 else{ 35 m = Depth(T->lchild); // 递归计算左子树深度 36 n = Depth(T->rchild); // 递归计算右子树深度 37 if(m>n) 38 return m+1; // 返回左右子树最大值加1 39 else 40 return n+1; 41 } 42 } 43 44 int main(){ 45 Btree mytree; 46 cout << "按先序次序输入二叉树中国结点的值(孩子为空是输入#),创建一颗二叉树" << endl; 47 // ABD##E##CF#G### 48 Createtree(mytree); // 创建二叉树 49 cout << endl; 50 cout << "二叉树的深度为:" << Depth(mytree) << endl; 51 return 0; 52 }
ABD##E##CF#G### 按先序次序输入二叉树中国结点的值(孩子为空是输入#),创建一颗二叉树 二叉树的深度为:4 Program ended with exit code: 0
题目二:二叉树遍历 前序、中序、后序、层次遍历
1 #include <iostream> 2 #include <queue> 3 using namespace std; 4 5 struct Bonde{ 6 char data; 7 struct Bonde *lchild, *rchild; 8 }; 9 10 typedef struct Bonde Bonde; 11 typedef struct Bonde *Btree; 12 13 void Createtree(Btree &T){ 14 char ch; 15 cin >> ch; 16 if(ch == '#') 17 T = NULL; 18 else{ 19 T = new Bonde; 20 T->data = ch; 21 Createtree(T->lchild); 22 Createtree(T->rchild); 23 } 24 } 25 26 void preorder(Btree T){ // 先序遍历 27 if(T){ 28 cout << T->data << " "; 29 preorder(T->lchild); 30 preorder(T->rchild); 31 } 32 } 33 34 void inorder(Btree T){ // 中序遍历 35 if (T) { 36 inorder(T->lchild); 37 cout << T->data << " "; 38 inorder(T->rchild); 39 } 40 } 41 42 void posorder(Btree T){ // 后序遍历 43 if (T) { 44 posorder(T->lchild); 45 posorder(T->rchild); 46 cout << T->data << " "; 47 } 48 } 49 50 // 只有通过指针才能调用左右孩子 51 bool Leveltraverse(Btree T){ // 层次遍历 52 Btree p; 53 if(!T) 54 return false; 55 queue<Btree> Q; // 创建一个普通队列(先进先出),里面存放指针类型 56 Q.push(T); // 根指针入队 57 while (!Q.empty()) { 58 p = Q.front(); // 取出对头元素作为当前扩展节点livenode 59 Q.pop(); // 队头元素出队 60 cout << p->data << " "; 61 if(p->lchild) 62 Q.push(p->lchild); // 左孩子入队 63 if(p->rchild) 64 Q.push(p->rchild); // 右孩子入队 65 } 66 return true; 67 } 68 69 70 int main(){ 71 Btree mytree; 72 cout << "按先序层次输入二叉树中结点的值(孩子为空时输入#),创建一颗二叉树" << endl; 73 Createtree(mytree); // 创建二叉树 74 cout << endl; 75 cout << "二叉树的先序遍历结果:" << endl; 76 preorder(mytree); // 先序遍历二叉树 77 cout << endl; 78 cout << "二叉树的中序遍历结果:" << endl; 79 inorder(mytree); // 中序遍历二叉树 80 cout << endl; 81 cout << "二叉树的后序遍历结果:" << endl; 82 posorder(mytree); // 后序遍历二叉树 83 cout << endl; 84 cout << "二叉树的层次遍历结果:" << endl; 85 Leveltraverse(mytree); // 层次遍历二叉树 86 return 0; 87 }
按先序层次输入二叉树中结点的值(孩子为空时输入#),创建一颗二叉树 ABD##E##CF#G### 二叉树的先序遍历结果: A B D E C F G 二叉树的中序遍历结果: D B E A F G C 二叉树的后序遍历结果: D E B G F C A 二叉树的层次遍历结果: A B C D E F G
Program ended with exit code: 0
题目三:二叉树还原 先序和中序得二叉树 后序和中序得二叉树
思路:
- 先序找根
- 中序分左右
函数(先序序列开始位置, 中序序列开始位置, 序列长度)
1 #include <iostream> 2 using namespace std; 3 4 typedef struct node{ 5 char data; 6 struct node *lchild, *rchild; 7 }BiTNode, *BiTree; 8 9 // 也就是说BitNode是struct的别名,BiTree是struct的指针,指针只是指向地址对象的,不能用来创建对象,而BitNode是可以用来创建对象实体的 10 11 BiTree pre_mid_createBiTree(char *pre, char *mid, int len){ // 前序中序还原建立二叉树 12 if(len == 0) 13 return NULL; 14 char ch = pre[0]; // 找打先序序列中的第一个结点 15 int index = 0; 16 while(mid[index]!=ch){ // 在中序中 17 index++; 18 } 19 BiTree T = new BiTNode; // 创建根节点 20 T->data = ch; 21 T->lchild = pre_mid_createBiTree(pre+1, mid, index); // 建立右子树 22 T->rchild = pre_mid_createBiTree(pre+index+1, mid+index+1, len-index-1); // 建立右子树 23 return T; 24 } 25 26 BiTree pro_mid_createBiTree(char *last, char *mid, int len){ // 后序中序还原二叉树 27 if(len==0) 28 return 0; 29 char ch = last[len-1]; // 取到后序遍历顺序中最后一个结点 30 int index = 0; // 在中序序列中找根节点,并用index记录长度 31 while (mid[index]!=ch)// 在中序序列中找根节点,左边边为该节点的左子树,右边为右子树 32 index++; 33 BiTree T = new BiTNode; // 创建根结点 34 T->data= ch; 35 T->lchild = pro_mid_createBiTree(last, mid, index); // 建立左子树 36 T->rchild = pro_mid_createBiTree(last+index, mid+index+1, len-index-1); // 建立右子树 37 return T; 38 } 39 40 void pre_order(BiTree T){ 41 if(T){ 42 cout << T->data; 43 pre_order(T->lchild); 44 pre_order(T->rchild); 45 } 46 } 47 48 void pro_order(BiTree T){ 49 if(T){ 50 pro_order(T->lchild); 51 pro_order(T->rchild); 52 cout << T->data; 53 } 54 } 55 /* 56 7 57 A B D E C F G 58 D B E A F G C 59 D E B G F C A 60 */ 61 int main(){ 62 BiTree T; 63 int n; 64 char pre[100], mid[100], last[100]; 65 cout << "1.前序中序还原二叉树 "; 66 cout << "2.后序中序b还原二叉树 "; 67 int choose = -1; 68 while (choose!=0) { 69 cout << "请选择:"; 70 cin >> choose; 71 72 switch (choose) { 73 case 1: 74 cout << "请输入节点的个数:" << endl; 75 cin >> n; 76 cout << "请输入前序序列:" << endl; 77 for(int i=0; i<n; i++) 78 cin >> pre[i]; 79 cout << "请输入中序序列:" << endl; 80 for(int i=0; i<n; i++) 81 cin >> mid[i]; 82 T = pre_mid_createBiTree(pre, mid, n); 83 cout << endl; 84 cout << "二叉树还原成功,输出其后序序列:" << endl; 85 pro_order(T); 86 cout << endl << endl; 87 break; 88 case 2: 89 cout << "请输入节点的个数:" << endl; 90 cin >> n; 91 cout << "请输入后序序列:" << endl; 92 for(int i=0; i<n; i++) 93 cin >> last[i]; 94 cout << "请输入中序序列:" << endl; 95 for(int i=0; i<n; i++) 96 cin >> mid[i]; 97 T = pro_mid_createBiTree(last, mid, n); 98 cout << endl; 99 cout << "二叉树还原成功,输出其先序序列:" << endl; 100 pre_order(T); 101 cout << endl << endl; 102 break; 103 } 104 } 105 return 0; 106 }
1.前序中序还原二叉树 2.后序中序b还原二叉树 请选择:1 请输入节点的个数: 7 请输入前序序列: A B D E C F G 请输入中序序列: D B E A F G C 二叉树还原成功,输出其后序序列: DEBGFCA
题目四:二叉树的 叶子数 结点数
1 #include <iostream> 2 using namespace std; 3 4 typedef struct Bnode{ 5 char data; 6 struct Bnode *lchild, * rchild; 7 }Bnode, *Btree; 8 9 void Createtree(Btree &T){ // 引用传递 需要对T的进行修改的时候使用Btree &T, 不需要修改时候使用Btree T 10 char ch; 11 cin >> ch; 12 if(ch == '#') 13 T = NULL; 14 else 15 { 16 T = new Bnode; 17 T->data = ch; 18 Createtree(T->lchild); 19 Createtree(T->rchild); 20 } 21 } 22 23 int NodeCount(Btree T){ 24 // 求二叉树的结点个数 25 if(T == NULL) 26 return 0; 27 else 28 return NodeCount(T->lchild)+NodeCount(T->rchild)+1; // 递归计算左右子树结点数之和 29 } 30 31 int LeafCount(Btree T){ 32 if(T == NULL) 33 return 0; 34 else 35 if(T->lchild==NULL && T->rchild==NULL) // 左右子树均为空为子叶节点,则叶子数为1 36 return 1; 37 else 38 return LeafCount(T->lchild)+LeafCount(T->rchild); // 递归计算左右子树叶子节点之和 39 } 40 41 int main(){ 42 Btree mytree; 43 cout << "按先序输入二叉树结点的值(孩子为空时输入#),创建一颗二叉树" << endl; 44 // AB##E##CF#G### 45 Createtree(mytree); 46 cout << endl; 47 cout << "二叉树结点是为:" << NodeCount(mytree) << endl; 48 cout << "二叉树叶子数为:" << LeafCount(mytree) << endl; 49 return 0; 50 }