树中有一些概念需要我们了解,节点的度是指该节点子树的个数,树的度是指树中节点度得最大值,一个树的深度是指树中节点最大层次值。二叉树是数据结构中一种重要的结构,它有很多重要的性质:
1)二叉树第i层上最多有2i-1个节点;
2)深度为k的二叉树各层节点总数最多为2k-1;
3)在任意的二叉树中,如果叶子节点个数为n0,度为1的节点个数为n1,度为2的节点的个数为n2,则n2=n0+1;
4)具有n个节点的完全二叉树,其树的深度为log2n向下取整再加1;
5)对有n个节点的二叉树从1到n的顺序进行编号,则对于编号为i的节点(i>=1)有:
当i=1时,该节点为树根;
当i>1时,该节点的双亲节点为i/2向下取整;
当2i<=n时,该节点有编号为2i的的左孩子;
当2i+1<=n时,该节点有编号为2i+1的右孩子。
此篇博客主要记载本人对二叉树如何建立,遍历的一些知识。
二叉树的建立算法还是相对繁琐的,这里面主要介绍两种二叉树的简历方法:1)对树中所有节点进行编号,输入相应节点的数值的方法;2)使用递归的方式,按照遍历的方式输入树节点的遍历序列。
首先看看第一种方式,所需要输入的信息有节点编号和节点存储的数值,借助一个辅助向量用于存储指向每个节点的指针,具体算法如下:
当输入的节点编号为1时,此时它是根节点,同时将指向该节点的指针存放在s[1]中。
当输入的节点编号i大于1时,先将其存入s[i]中,然后可以知道其双亲节点为j=i/2;
如果i为偶数,它是双亲的左孩子,则有s[j]->lchild=s[i];
如果i为奇数,它是双亲的右孩子,则有s[j]->rchild=s[i];
这样就可以输入多个节点组成一个二叉树,而且逐步将孩子与双亲节点建立连接。
第二种方式就是递归的建立二叉树了:具体思路可以见后面的代码。
建立好了二叉树,我们最应该掌握的算法就是对二叉树的遍历了。
二叉树的遍历有先序遍历,中序遍历,后序遍历和层序遍历四种。有递归实现和非递归实现,这些我们都应该掌握。
/*********Shanghai Jiaotong EE zhouguiyin*********/ /*******************Tree practice*****************/ #include <iostream> using namespace std; typedef int Elemtype; class Treenode { public: Elemtype data; Treenode *lchild, *rchild; }; class Tree { public: Tree(){root = NULL;} ~Tree(){destroy(root);root=NULL;} void Creat1(); //创建一个二叉树,按照先序遍历递归建立二叉树 void Creat2(); //创建一个二叉树,按照编号元素建立二叉树 void Preorder() {preorder(root);} void Inorder() {inorder(root);} void Postorder() {postorder(root);} private: Treenode *root; Treenode* creat_bt(); void destroy(Treenode*); void preorder(Treenode*); void inorder(Treenode*); void postorder(Treenode*); }; void Tree::Creat1() { cout<<"请按照先序遍历写出要输入的元素流,空孩子以0代替"<<endl; root=creat_bt(); } Treenode* Tree::creat_bt() { Treenode *t; int num; cin>>num; if (num==0) t=NULL; else { t=new Treenode; t->data = num; t->lchild=creat_bt(); t->rchild=creat_bt(); } return t; } void Tree::Creat2() { Treenode*p, *s[10]; int i,m; cout<<"请输入编号顺序(根节点序号为1)及相应的节点元素值"<<endl; cin>>i>>m; while((i>0)&&(m>0)) { p=new Treenode; s[i] = p; p->data = m; p->lchild = NULL; p->rchild = NULL; if (i==1) root = p; else { if(i%2==0) s[i/2]->lchild=p; else s[i/2]->rchild=p; } cout<<"请输入编号顺序(根节点序号为1)及相应的节点元素值"<<endl; cin>>i>>m; } } void Tree::preorder(Treenode*p) { if(p!=NULL) { cout<<p->data; preorder(p->lchild); preorder(p->rchild); } } void Tree::inorder(Treenode*p) { if(p!=NULL) { inorder(p->lchild); cout<<p->data; inorder(p->rchild); } } void Tree::postorder(Treenode*p) { if(p!=NULL) { preorder(p->lchild); preorder(p->rchild); cout<<p->data; } } void Tree::destroy(Treenode *p) { if (p!=NULL) { destroy(p->lchild); destroy(p->rchild); delete p; } } int main() { Tree tree; tree.Creat1(); tree.Preorder(); tree.Creat2(); tree.Preorder(); }
上面的遍历算法均为递归的,非递归实现如下
/*******************二叉树先序非递归遍历******************/ /**************Shanghai Jiaotong EE zhouguiyin************/ void Tree::Preorder() { Stack<Treenode*> s; Treenode *p = root; int x = 1; do { while(p!=NULL) {cout<<p->data; s.push(p); p=p->lchild;} if (s.Isempty_stack()) x=0; else { p=s.pop(); p=p->rchlid; } }while(x); } /*******************二叉树中序非递归遍历******************/ /**************Shanghai Jiaotong EE zhouguiyin************/ void Tree::Inoreder() { Stack<Treenode*> s; Treenode *p = root; int x = 1; do { while(p!=NULL) {s.push(p); p=p->lchild;} if (s.Isempty_stack()) x=0; else { p=s.pop(); cout<<p->data; p=p->rchlid; } }while(x); } /*******************二叉树后序非递归遍历******************/ /**************Shanghai Jiaotong EE zhouguiyin************/ void Tree::postoreder() { Stack<Treenode*> s,Stack<int> t; Treenode *p = root; Treenode *q; int x = 1; do { while(p!=NULL) {s.push(p); t.push(1); p=p->lchild;} if (s.Isempty_stack()) x=0; else { if(t.Gettop()==1) { t.pop(); t.push(2);q = s.Gettop();q=q->rchild;} else { q=s.pop(); t.pop(); cout<<q->data; q=NULL; } } }while(x); } /*******************二叉树层序非递归遍历******************/ /**************Shanghai Jiaotong EE zhouguiyin************/ void Tree::leveloreder() { Queue<Treenode*> s; Treenode* p; p=root; if (p!=NULL) s.Addqueue(p); while(!s.Isempty()) { p=s.Dequeue(); cout<<p->data; if(p->lchild!=NULL) s.Addqueue(p->lchild); if(p->rchild!=NULL) s.Addqueue(p->rchild); } }
二叉树的操作除了建立和遍历以外,还可以考察一些操作,比如统计一下树中节点的总数,有多少个叶子节点,或者是问问树的深度是多少之类的问题,下面是以上3个问题的C++代码:
/*******************二叉树节点个数统计******************/ /**************Shanghai Jiaotong EE zhouguiyin************/ void Tree::num_node(Treenode* p,int &count) { /*此处在调用num_node时,需要传递一个计数的整形变量,初始化应为0*/ if (p!=NULL) { num_node(p->lchild,count); count++; num_node(p->rchild,count); } } /*******************二叉树叶子节点个数统计******************/ /**************Shanghai Jiaotong EE zhouguiyin************/ void Tree::num_leafnode(Treenode* p,int &count) { /*此处在调用num_leafnode时,需要传递一个计数的整形变量,初始化应为0*/ if (p!=NULL) { num_leafnode(p->lchild,count); if(p->lchild==NULL && p ->rchild==NULL)count++; num_leafnode(p->rchild,count); } } /*******************二叉树深度计算******************/ /**************Shanghai Jiaotong EE zhouguiyin************/ int Tree::depth(Treenode* p) { if (p!=NULL) { return 1+max(depth(p->lchild),depth(p->rchild)); else return 0; } } int Tree::max(int A, int B) { return(A>=B?A:B); }