序:二叉树作为树的一种,是一种重要的数据结构,常见的二叉树有:
满二叉树:除叶子结点外,所有结点都有两个结点,叶子结点的left,right为NULL.
哈夫曼树:又称为最优二叉数,是一种带权路径最短的树。哈夫曼编码就是哈夫曼树的应用,可以用来进行编码压缩.哈夫曼树的构造见哈夫曼树的构造
完全二叉树:除了最底层的叶子结点之外,其余层全满,而且叶子层集中在左端.堆是一种特殊的完全二叉树(全满或者差一个结点就全满)
平衡二叉树:所谓平衡二叉树指的是,左右两个子树的高度差的绝对值不超过 1。包括AVL树,红黑树.
红黑树:具体见红黑树问题
下面是我总结的这几天看过的一些常见二叉树问题.
1.二叉搜索树的迭代构造
二叉搜索树是一棵排好序的树,当新插入一个节点的时候,小于当前根结点左走,大于当前根结点右走,直至走到NULL点,就是该结点的位置.
void IterativeInsert(Tree* T,node* z)//插入节点 { node* y=NULL; node* x=T->root;//管理两个指针,父指针y,y的子树指针x while(x!=NULL)//一直向下遍历到z应该插入的位置 { y=x; if(x->value < z->value) x=x->right; else x=x->left; } z->p=y;//先将z的父指针p指向y if(y==NULL)//若树为空,树根即为z T->root=z; else if(z->value < y->value)//否则分插入左边还是右边 y->left=z; else y->right=z; }
2.二叉搜索树的递归构造
1.若是空树,则插入至根结点位置
2.若比当前根点,插入左边.
3.否则插入右边
node* TreeInsert(node* root,node* z) { if(!root) root=z; else if(root->value < z->value) root->right=TreeInsert(root->right,z); else root->left=TreeInsert(root->left,z); return root; }
3.二叉树三种递归遍历方式.
void InorderTreeWalk(node* root) { if(!root ) return ; InorderTreeWalk(root->left); cout<<root->value<<' '; InorderTreeWalk(root->right); } void PriorTreeWalk(node* root) { if(!root ) return ; cout<<root->value<<' '; PriorTreeWalk(root->left); PriorTreeWalk(root->right); } void PostTreeWalk(node* root) { if(!root ) return ; PostTreeWalk(root->left); PostTreeWalk(root->right); cout<<root->value<<' '; }
4.二叉树三种迭代遍历方式.
深度优先原则,输出顺序是'左子树优先'
void IterativeInorderWalk(node *root)//迭代中序遍历 { node* p=root; stack<node*> st;//利用栈 if(!p) //if(!p)=if(p==null) return ; while(p || !st.empty())//当p不为空 或者st不为空 { while(p)//沿着左孩子方向走到最左下。同时压栈 { st.push(p); p=p->left; } p=st.top();//获取栈顶元素 cout<<p->value<<" "; st.pop(); p=p->right; } } void IterativePriorTreeWalk(node* root)//迭代先序遍历 { node* p=root; stack<node* > st; if(!p) return ; while(p || !st.empty()) { while(p) { cout<<p->value<<" "; st.push(p); p=p->left; } p=st.top(); st.pop(); p=p->right; } } void IterativePostWalk(node* root) { node* p=root; stack<node* > st; node* pre=NULL;//pre表示最近一次访问的结点 if(!p) return ; while(p || !st.empty()) { while(p) //沿着左孩子方向走到最左下 { st.push(p); p=p->left; } p=st.top(); //获取栈顶元素 if( !p->right || p->right ==pre)//如果p没有右孩子或者其右孩子刚刚被访问过.小窍门if (!p)表示如果p为空 { st.pop(); cout<<p->value<<' '; pre=p; //最近一次访问的节点是p p=NULL; //使下一次循环不再执行p节点以下的压栈操作 } else p=p->right; } }
5.怎样从根结点开始逐层打印二叉树结点数据.
广度优先原则,需要用到队列,当访问一个当前节点CurrentNode的时候,将该结点出队,同时将该CurrentNode的左右子结点入队,重复这个操作,直至队列为空.步骤:1初始化队列.2重复出队入队操作直至队列为空.
//从顶部开始逐层打印二叉树结点数据,即广度遍历二叉树,需要用到队列 void printHori(node* root) { if(!root) return ; queue<node*> Q; Q.push(root); while(!Q.empty()) { nod