1、二叉树(Binary Tree)是一种特殊的树形结构:每个结点至多有两棵子树,即二叉树中不存在度大于2的结点。
2、二叉树的子树有左右之分,次序不能任意颠倒。
3、性质1:二叉树的第i层上至多有2^(i-1)个结点,i从1下标开始。所有
4、性质2:深度为k的二叉树至多有2^k -1个结点,k也是从1下标开始。
5、性质3:对于任何一棵二叉树,如果终端结点数为n0,度为2的结点数为n2,则n0 = n2+1。这个很简单:
(1)设度为1的结点数为n1,则总结点数n = n0 + n1 + n2。
(2)根据先前的(任意树)上的公式:结点数量 = 所有结点度之和 + 1,即n = n0+ n1 + n2 = n1 + 2 n2 +1,两边消掉,有:
n0 = n2 + 1。
6、满二叉树:一棵深度为k,且有2^k -1个结点的二叉树。特点是每一层都是满的。
7、完全二叉树:不是满二叉树!它的结点可以不足2^k - 1,但是深度必须和对应的满二叉树对应,已经有的结点从1~k必须和同深度的满二叉树一一对应(即在满二叉树的第k层从右向左去掉若干个结点,至少保留一个结点)。
8、满二叉树是完全二叉树,但完全二叉树不是满二叉树!
9、性质4:具有n个结点的完全二叉树,深度为[ log(n)] + 1,其中[]是向下取整。
10、性质5:如果对一棵有n个结点的完全二叉树的结点按层次编号,每层从左到右,层次从上到下。假设根存储在1号单元(设下标从1开始),对任意结点i,
(1) 如果i=1,结点i是二叉树的根,无双亲。i>1,则双亲PARENT(i)是结点[i/2],还是向下取整。
(2) 如果2i>n,则结点无左孩子,否则左孩子是2i。
(3)如果2i+1>n,无右孩子,否则右孩子是2i+1。
如果下标从0开始,上述结论变成:
(1)双亲是i/2-1
(2)左孩子是2i+1,>n无左孩子。
(3)右孩子是2i+2,>n无右孩子。
11、二叉树的遍历,先序、中序、后序遍历分别对应着表达式:前缀表示(又叫波兰式)、中缀表示和后缀表示(又叫逆波兰式)。
二叉树的顺序存储
利用上述性质5,可以把任何一个二叉树映射到完全二叉树上,从而映射到数组上。当然这个数组的中间某些位置可能是“空的”。
代码:包含创建、先、中后序遍历(递归版本)
#include <stdio.h> #include <string.h> #define MAX 100 #define EMPTY_NODE -1 struct BiTree { int data[MAX]; }; void btree_create(struct BiTree* tree, int* data, int n) { int i = 0; memset(tree->data, -1, sizeof(int)*MAX); for(i = 0; i<n && i<MAX; i++) { tree->data[i] = data[i]; // EMPTY_NODE stores as EMPTY_NODE } } void btree_pre_order(struct BiTree* tree, int pos) { int left = 0, right = 0; if(pos >=MAX || tree->data[pos]==EMPTY_NODE) { return ; } // Mid printf("%d ", tree->data[pos]); left = pos*2 + 1; right = pos*2 + 2; // Left, Right btree_pre_order(tree, left); btree_pre_order(tree, right); if(pos==0) { printf("\n"); } } void btree_in_order(struct BiTree* tree, int pos) { int left = 0, right = 0; if(pos >=MAX || tree->data[pos]==EMPTY_NODE) { return ; } // Left left = pos*2 + 1; btree_in_order(tree, left); // Mid printf("%d ", tree->data[pos]); // Right right = pos*2 + 2; btree_in_order(tree, right); if(pos==0) { printf("\n"); } } void btree_post_order(struct BiTree* tree, int pos) { int left = 0, right = 0; if(pos >=MAX || tree->data[pos]==EMPTY_NODE) { return ; } // Left left = pos*2 + 1; btree_post_order(tree, left); // Right right = pos*2 + 2; btree_post_order(tree, right); // Mid printf("%d ", tree->data[pos]); if(pos==0) { printf("\n"); } } int main() { int data[7] = {1, 2, 3, 4, 5, EMPTY_NODE, 7}; struct BiTree tree; // Create btree_create(&tree, data, 7); // Pre-order print btree_pre_order(&tree, 0); // In-order print btree_in_order(&tree, 0); // Post-order print btree_post_order(&tree, 0); return 0; }
下面来说说非递归的:
首先是先序非递归,很简单,就是先visit,然后右压栈,然后左压栈。
void btree_pre_order_fdg(struct BiTree* tree) { struct Stack stack; int tmp; stack_init(&stack); stack_push(&stack, 0); while(!stack_is_empty(&stack)) { if(stack_pop(&stack, &tmp)==0) { if(tree->data[tmp]!=EMPTY_NODE) { printf("%d ", tree->data[tmp]); stack_push(&stack, tmp*2+2); // stack push right first stack_push(&stack, tmp*2+1); // stack push left then } } } printf("\n"); }
下面讨论下非递归的版本:
首先中序非递归遍历,略复杂一点:
(1)先root入栈
(2)对所有左子树入栈,直到到达左下角。
(3)依次出栈,对每个出栈元素先visit,然后入右子树,也是循环,直到右下角。
void btree_in_order_fdg(struct BiTree* tree) { struct Stack stack; int tmp; stack_init(&stack); stack_push(&stack, 0); // push root while(!stack_is_empty(&stack)) { if(stack_top(&stack, &tmp)==0) { // Push all left children while not EMPTY_NODE while((tmp*2+1)<MAX && tree->data[(tmp*2+1)!=EMPTY_NODE]) { tmp = tmp * 2 +1; stack_push(&stack, tmp); } // Pop one left, print current, push right while(!stack_is_empty(&stack)) { if(stack_pop(&stack, &tmp)==0) { if(tree->data[tmp]!=EMPTY_NODE) { printf("%d ", tree->data[tmp]); if((tmp*2+2)<MAX && tree->data[(tmp*2+2)]!=EMPTY_NODE) { stack_push(&stack, tmp*2+2); } } } } } } printf("\n"); }
后序非递归:比较复杂,还没写出来。
层序遍历,需要借助队列,比较简单,代码如下:
void btree_level(struct BiTree* tree) { struct Queue queue; int tmp; queue_init(&queue); queue_enqueue(&queue, 0); // enqueue root while(!queue_is_empty(&queue)) { // Visit if(0==queue_dequeue(&queue, &tmp)) { if(tmp<MAX && tree->data[tmp]!=EMPTY_NODE) { printf("%d ", tree->data[tmp]); // enqueue left and right queue_enqueue(&queue, tmp*2+1); queue_enqueue(&queue, tmp*2+2); } } } }
二叉树的链式存储
基础部分不用多解释了。
#include <iostream> #include <stack> #define EMPTY_NODE -1 struct BiTree { struct BiTree* left; struct BiTree* right; int data; bool tag; }; void bitree_init(struct BiTree* tree) { tree->left = tree->right = NULL; tree->data = EMPTY_NODE; } // Use pre order with EMPTY flag to crate btree int i = 0; void bitree_create(struct BiTree*& tree, int* data, int n) { if(i>=n || data[i]==EMPTY_NODE) { tree = NULL; }else { tree = new BiTree; tree->data = data[i]; tree->tag = false; i++; bitree_create(tree->left, data, n); i++; bitree_create(tree->right, data, n); } } // Pre-order Traverse void bitree_pre_order(struct BiTree* tree) { if(tree && tree->data!=EMPTY_NODE) { ::std::cout << tree->data << " "; bitree_pre_order(tree->left); bitree_pre_order(tree->right); } } // Post-order Traverse void bitree_post_order(struct BiTree* tree) { if(tree && tree->data!=EMPTY_NODE) { bitree_post_order(tree->left); bitree_post_order(tree->right); ::std::cout << tree->data << " "; } } int main() { struct BiTree* bt = NULL; int data[11] = {1, 2, 4, EMPTY_NODE, EMPTY_NODE, 5, EMPTY_NODE, EMPTY_NODE, 3, EMPTY_NODE, 7 }; // BiTree create bitree_create(bt, data, 11); // Pre-order //bitree_pre_order(bt); //::std::cout << ::std::endl; // Post-order bitree_post_order(bt); ::std::cout << ::std::endl;; return 0; }
然后重点关注下非递归实现后序遍历:
算法分为三个部分:
(1)大循环,条件ptr!=NULL或者栈非空
(2)循环内1:压所有左子树,直到左下角
(3)循环内2:对于stack的top结点,如果是第一次visit(tag==false),将它置为tag==true,然后ptr设为右子树。如果是第二次,说明右子树已经访问过了,直接访问自身,然后设置为NULL。
// Post-order Traverse void bitree_post_order_fdg(struct BiTree* root) { ::std::stack<BiTree*> stk; BiTree* ptr = root; while(ptr!=NULL || !stk.empty()) { // Push while has left children while(ptr!=NULL) { stk.push(ptr); ptr = ptr->left; } // Twice visit if(!stk.empty()) { ptr = stk.top(); if(!ptr->tag) { // First visit ptr->tag = true; ptr = ptr->right; } else { // Second visit, means right children has been visited ::std::cout << ptr->data << " "; stk.pop(); ptr = NULL; } } } }
二叉树求深度
采用递归的方法,max(左子树深度, 右子树深度) +1
int bitree_depth(struct BiTree* tree) { if(tree==NULL) { return 0; }else { int ld = bitree_depth(tree->left); int rd = bitree_depth(tree->right); // return max(left_depth, right_depth) + 1 return (ld>rd?ld:rd)+1; } }