1. 普通二叉树
关于二叉树的深度和高度涉及到结点的层数,有的教材规定根结点在第0层,有的则规定根结点在第1层。
以《数据结构-C语言版》(严蔚敏,吴伟民版)的为准:高度和深度是同一个概念,根节点在第1层,树的高度是看一共有几层。 高度为h的完全二叉树,最多有2^n-1个节点,第k层最多有2^(k-1)个节点。 含有n个节点的完全二叉树,高度为(logn + 1)下取整。
对于完全二叉树:
如果第一个元素下标为1,则第k个元素的左孩子为2*k,右孩子为2*k+1,父节点为 k / 2 下取整,最后一个父节点为 length / 2 下取整。 如果第一个元素下标为0,则第k个元素的左孩子为2*k+1,右孩子为2*k+2,父节点为 (k - 1)/ 2 下取整,最后一个父节点为 length / 2 下取整 - 1。 二叉树的前驱后继节点,表示中序遍历时,一个节点的前一个和后一个。
高度为h的完全二叉树,最多有2^h-1个节点。
节点为n的完全二叉树,高度为logn。(高度为0的树有1个结点)。
- 1.2 二叉树的遍历
二叉树的有三种遍历方式,先中后序遍历,“先、中、后”表示根节点的遍历时间。
先序:先遍历分支的根节点,再遍历左子树,最后遍历右子树。
先序序列:ABDFECGHI
中序:先遍历分支的左子树,再遍历根节点,最后遍历右子树。
中序序列:DBEFAGHCI
后序:先遍历分支的左子树,再遍历右子树,最后遍历根节点。
后序序列:DEFBHGICA
通过包含中序序列(通过前后序列创建出的二叉树不唯一)的两个序列推出 剩余的一个序列,算法分别用前中推后,中后推前。
typedef struct BinaryTreeNode { ElemType data; struct BinaryTreeNode *Left; struct BinaryTreeNode *Right; }*BinaryTree; void PreAndInToPost(ElemType* pre, ElemType* in,int length) { if (length == 0) return; int rootIndex; BinaryTree BT = new BinaryTreeNode; BT->data = *pre; for (rootIndex = 0; in[rootIndex] != *pre; rootIndex++); PreAndInToPost(pre + 1, in, rootIndex); PreAndInToPost(pre + rootIndex + 1, in + rootIndex + 1, length - (rootIndex + 1)); cout << BT->data << " "; } void PostAndInToPre(ElemType* in, ElemType* post,int length) { if (length == 0) return; int rootIndex; BinaryTree BT = new BinaryTreeNode; BT->data = *(post + length - 1); for (rootIndex = length - 1; in[rootIndex] != *(post + length - 1); rootIndex--); cout << BT->data << " "; PostAndInToPre(in, post, rootIndex); PostAndInToPre(in + rootIndex + 1, post + rootIndex, length - (rootIndex + 1)); }
二叉树的三种遍历实现(递归+非递归):
后序遍历非递归,是借用两个栈A,B,用A栈访问,压栈顺序为中左右(先序为中右左),把这些节点再存到B栈里,最后一起出栈。
//先序 void preorderUnRecur(BTree T) { stack<BTree>s; s.push(T); while (!s.empty()) { T = s.top(); s.pop(); cout << T->data << " "; if (T->Right) s.push(T->Right); if (T->Left) s.push(T->Left); } cout << endl; } //中序 void inorderUnRecur(BTree T) { if (!T)return; stack<BTree>s; while (!s.empty() || T) { if (T) { s.push(T); T = T->Left; } else { T = s.top(); s.pop(); cout << T->data << " "; T = T->Right; } } cout << endl; } //后序 void postorderUnRecur(BTree T) { if (!T)return; stack<BTree>s1,s2; s1.push(T); while (!s1.empty()) { T = s1.top(); s1.pop(); s2.push(T); if (T->Left)s1.push(T->Left); if (T->Right)s1.push(T->Right); } while (!s2.empty()) { cout << s2.top()->data << " "; s2.pop(); } cout << endl; }
递归实现,相比来说就比较简单了:
void Inorder(BTree BT) { if (!BT)return; Inorder(BT->Left); cout << BT->data << " "; Inorder(BT->Right); } void Preorder(BTree BT) { if (!BT)return; cout << BT->data << " "; Preorder(BT->Left); Preorder(BT->Right); } void Postorder(BTree BT) { if (!BT)return; Postorder(BT->Left); Postorder(BT->Right); cout << BT->data << " "; }
-
1.3 二叉树的构建
二叉树的建立一般有两种方法:
(1)用数组的方式,或者一个个输入,按照节点的顺序,用一个特殊值(比如0,# )表示当前位置没有节点。但这样总归是会出现冲突的,比如节点的值就是0, # 的ASCII值。就不做写了。
(2)给定包含中序序列的两个序列。以下为 给定前序、中序序列时,创建二叉树。
1 #include <iostream> 2 using namespace std; 3 4 typedef char ElemType; 5 6 typedef struct BinaryTreeNode 7 { 8 ElemType data; 9 struct BinaryTreeNode *Left; 10 struct BinaryTreeNode *Right; 11 }*BinaryTree; 12 13 BinaryTree CreatBTFromPreAndIn(ElemType* pre, ElemType* in, int length) { 14 if (length == 0) return NULL; 15 int rootIndex; 16 BinaryTree BT = new BinaryTreeNode; 17 //将当前根节点入树 18 BT->data = *pre; 19 for (rootIndex = 0; in[rootIndex] != *pre; rootIndex++); 20 BT->Left = CreatBTFromPreAndIn(pre+1, in,rootIndex); 21 BT->Right = CreatBTFromPreAndIn(pre+rootIndex+1, in+rootIndex+1,length-(rootIndex+1)); 22 return BT; 23 } 24 BinaryTree CreatBTFromPostAndIn(ElemType* in, ElemType* post, int length) { 25 if (length == 0) return NULL; 26 int rootIndex; 27 BinaryTree BT = new BinaryTreeNode; 28 //将当前根节点入树 29 BT->data = *(post + length - 1); 30 for (rootIndex = length - 1; in[rootIndex] != *(post + length - 1); rootIndex--); 31 BT->Left = CreatBTFromPostAndIn(in, post, rootIndex); 32 BT->Right = CreatBTFromPostAndIn(in + rootIndex + 1, post + rootIndex/*删掉post的最后一个*/, length - (rootIndex + 1)); 33 34 return BT; 35 } 36 37 38 void Inorder(BinaryTree BT) { 39 if (!BT)return; 40 Inorder(BT->Left); 41 cout << BT->data << " "; 42 Inorder(BT->Right); 43 } 44 void Preorder(BinaryTree BT) { 45 if (!BT)return; 46 cout << BT->data << " "; 47 Preorder(BT->Left); 48 Preorder(BT->Right); 49 } 50 void Postorder(BinaryTree BT) { 51 if (!BT)return; 52 Postorder(BT->Left); 53 Postorder(BT->Right); 54 cout << BT->data << " "; 55 } 56 57 int main() { 58 char pre[] = "ABDGHCEIF"; 59 char in[] = "GDHBAEICF"; 60 char post[]= "GHDBIEFCA"; 61 BinaryTree BT1 = CreatBTFromPreAndIn(pre, in, strlen(in)); 62 BinaryTree BT2 = CreatBTFromPostAndIn(in, post, strlen(in)); 63 Postorder(BT1); 64 cout << endl; 65 Preorder(BT1); 66 cout << endl; 67 return 0; 68 }
前序、中序序列构建二叉树图解:
1.4关于二叉树的小算法
- 二叉树的深度
int height(BinaryTree L) { if (L == NULL) return 0; int left = height(L->Left); int right = height(L->Right); return left >= right ? left + 1 : right + 1; }
- 小于O(n),给出完全二叉树的长度(就是不准遍历)
完全二叉树一般都是用数组存储的(而这个算法是改不成数组的),也都是通过计算找子树、父节点的,我觉得实际操作中这个意义不大。
主要是练习对完全二叉树的理解。
int nodeNum(Node head) { if (!head) return 0; bs(head, 1, mostLeftLevel(head, 1)); } int bs(Node head, int level, int height) { if (!head) return 1; if (mostLeftLevel(head->right, level + 1) == height) { return 1 << (height - level) + bs(head->right, level + 1, height); } else { return 1 << (height - level - 1) + bs(head->left, level + 1, height); } } int mostLeftLevel(Node head, int level) { Node p = head; while (p->left) { p = p->left; level++; } return level; }