二叉链表结构的二叉树模型,栈用自己写的模版,队列就不了 ,直接用STL的,不然代码太长了
文件"tree.h"
#include<iostream> #include<queue> #include<stack> using namespace std; template<class T> class My_stack; template<class T> class Node //结点类 { private: T data; Node<T> *next; public: Node() { next=NULL; } Node(T d) { data=d; next=NULL; } friend My_stack<T>; }; template<class T> class My_stack { private: Node<T> *head; public: My_stack() { head=new Node<T>(); } bool empty() const { return (head->next==0); } void push(T d) //入栈 { Node<T> *p=new Node<T>(d); p->next=head->next; head->next=p; } T top() //返回栈顶元素 { if(empty()) { cout<<"stack is empty."<<endl; exit(1); } Node<T> *p=head->next; T temp=p->data; return temp; } void pop() //弹出栈顶元素 { Node<T> *p=head->next; head->next=p->next; delete p; } }; class BinTree; class BinNode { private: int data; int tag;//用于作为是否为第一次入栈的标志 BinNode *lchild; BinNode *rchild; friend class BinTree; }; class BinTree { private: BinNode *root; public: BinTree() { root=0; } BinNode *Get_Root() { return root; } BinNode *Create_Tree(BinNode *r) //先序建立二叉树 { int d; cout<<"输入数据(0代表空):"; cin>>d; if(d==0) return NULL; else { r=new BinNode; r->data=d; r->lchild=Create_Tree(r->lchild); r->rchild=Create_Tree(r->rchild); } root=r; return r; } bool _empty() { return (root==0); } int Tree_Depth(BinNode *p) //求二叉树深度 { if(!p) return 0; int depth_l,depth_r; depth_l=Tree_Depth(p->lchild); depth_r=Tree_Depth(p->rchild); if(depth_l>depth_r) return depth_l+1; else return depth_r+1; } void PreOrder_rec(BinNode *p) //先序遍历 { if(p) { cout<<p->data<<" "; PreOrder_rec(p->lchild); PreOrder_rec(p->rchild); } } void InOrder_rec(BinNode *p) //中序遍历 { if(p) { InOrder_rec(p->lchild); cout<<p->data<<" "; InOrder_rec(p->rchild); } } void PostOrder_rec(BinNode *p) //后序遍历 { if(p) { PostOrder_rec(p->lchild); PostOrder_rec(p->rchild); cout<<p->data<<" "; } } void LevelOrder_rec(BinNode *p) //按层次遍历 { queue<BinNode *> q; do { cout<<p->data<<" "; if(p->lchild) q.push(p->lchild); if(p->rchild) q.push(p->rchild); p=q.front(); q.pop(); if(!p->lchild && !p->rchild && q.empty()) { cout<<p->data; return ; } }while(p); } BinNode *Copy(BinNode *p) //复制二叉树 { if(!p) return NULL; BinNode *newlchild,*newrchild; if(p->lchild) newlchild=Copy(p->lchild); else newlchild=NULL; if(p->rchild) newrchild=Copy(p->rchild); else newrchild=NULL; BinNode *NewNode=new BinNode; NewNode->data=p->data; NewNode->lchild=newlchild; NewNode->rchild=newrchild; return NewNode; } void Exchange(BinNode *p,My_stack<BinNode *> s) //交换左右子树 { if(p) { s.push(p); do { BinNode *t=s.top(); s.pop(); if(t->lchild || t->rchild) { BinNode *temp=t->lchild; t->lchild=t->rchild; t->rchild=temp; } if(t->lchild) Exchange(t->lchild,s); if(t->rchild) Exchange(t->rchild,s); }while(!s.empty()); } } int Leaf_rec(BinNode *p) //计算叶子结点数 { if(!p) return 0; if(p->lchild==0 && p->rchild==0) return 1; else { int m=Leaf_rec(p->lchild); int n=Leaf_rec(p->rchild); return m+n; } } int Is_CompleteBInTree(BinNode *p) //判断是不是完全二叉树 { //判断的方式是按层次遍历的方法,设置一个标志一开始为0; //一旦某个结点的左或右分支为空时,将标志置为1 //若此后遍历的结点的左右分支都为空 //则二叉树是完全二叉树,否则不是完全二叉树。 queue<BinNode *> q; int flag=0; if(!p) return 1; q.push(p); while(!q.empty()) { p=q.front(); q.pop(); if(p->lchild && !flag) q.push(p->lchild); else { if(p->lchild) //前面的条件不符合,要么是p->lchild为空 return 0; //要么是flag=1,这里就分别讨论了 else flag=1; } if(p->rchild && !flag) q.push(p->rchild); else { if(p->rchild) return 0; else flag=1; } } return 1; } void Ancestor(BinNode *p,int d) //求祖先 { if(!p) { cout<<"二叉树空"<<endl; return ; } if(p->data==d) { cout<<"因为"<<d<<"是根节点的值,所以没有祖先"<<endl; return ; } else { My_stack<BinNode *> s; BinNode *t=p; while(t || !s.empty()) { while(t && t->data!=d) { //将t的tag置为0,压进栈,先从左边开始 t->tag=0; s.push(t); t=t->lchild; } if(t && t->data==d) { cout<<"结点值为"<<d<<"的祖先为:"<<endl; while(!s.empty()) { BinNode *temp=s.top(); s.pop(); cout<<temp->data<<" "; } return ; } else { //t为空且data!=d BinNode *temp=s.top(); s.pop(); while(!s.empty() && temp->tag==1) { temp=s.top(); s.pop(); } if(temp->tag!=1) { temp->tag=1; s.push(temp); t=temp->rchild; } }//end_else(t==NULL) }//end_while }//end_else(t!=0 && t->data!=d) }//end void Counter(BinNode *r) //求每一层中,数据值大于某个值的总数,且分层输出 { int digit,*num,level,*nodesum; cout<<"将帮你比如统计每一层中不小于特定数字的结点总数并输出对应结点的值"<<endl; cout<<"输入你要作为比较标志的数字:"; cin>>digit; queue<BinNode *> q; queue<int> datas; //用来存放每一层总大于digit的结点值 int depth=Tree_Depth(r);//现求出树的深度 num=new int[depth+1];//为每一层申请一个空间,存放该层中不小于digit的结点总数 //为了看起来比较方便,num[0]不存数据,从num[1]开始存放,与level值相对应 nodesum=new int[depth+1]; //存下一层的结点总数 //初始化两个数组 for(int j=0;j<=depth;j++) num[j]=0; for(j=0;j<=depth;j++) nodesum[j]=0; //下面是先初始化第一层,然后再进入循环 level=1; if(r->data>=digit) num[level]++; if(r->lchild) { q.push(r->lchild); nodesum[2]++; } if(r->rchild) { q.push(r->rchild); nodesum[2]++; } if(num[level]) { cout<<"第"<<level<<"层中不小于"<<digit<<"的结点总数为:"<<num[level]<<"个"<<endl; cout<<"具体是:"<<r->data<<endl; } level++; for(;level<=depth;level++) { int p=level+1; for(int i=0;i<nodesum[level];i++) { r=q.front(); q.pop(); if(r->data>=digit) { num[level]++; datas.push(r->data); } if(r->lchild) { q.push(r->lchild); nodesum[p]++; } if(r->rchild) { q.push(r->rchild); nodesum[p]++; } } cout<<"第"<<level<<"层中不小于"<<digit<<"的结点总数为:"<<num[level]<<"个"<<endl; cout<<"具体是:"; while(!datas.empty()) { cout<<datas.front()<<" "; datas.pop(); } cout<<endl; } } void Out_Path(BinNode *r,stack<BinNode *> s) //求从根节点到叶子结点的路径 { if(r) { s.push(r); if(!r->lchild && !r->rchild) Print_stack(s); else { Out_Path(r->lchild,s); Out_Path(r->rchild,s); } } } void Print_stack(stack<BinNode *> s) { BinNode *p=NULL; int num[20],i=0; while(!s.empty()) { p=s.top(); s.pop(); num[i]=p->data; i++; } for(int j=i-1;j>0;j--) cout<<num[j]<<"->"; cout<<num[j]; cout<<endl; return; } };
测试文件"main.cpp"
#include"tree.h" #include<time.h> int main() { BinTree tree; if(tree._empty()) cout<<"二叉树为空"<<endl; BinNode *p; p=tree.Create_Tree(p); if(tree._empty()) cout<<"二叉树为空"<<endl; else cout<<"二叉树不空"<<endl; clock_t star=clock(),end(0); cout<<"先序遍历二叉树:"; tree.PreOrder_rec(p); cout<<endl; cout<<"中序遍历二叉树:"; tree.InOrder_rec(p); cout<<endl; cout<<"后序遍历二叉树:"; tree.PostOrder_rec(p); cout<<endl; cout<<"按层次遍历二叉树:"; tree.LevelOrder_rec(p); cout<<endl; end=clock(); cout<<"这段代码运行时间为:"<<(double)(end-star)<<"ms"<<endl; cout<<"二叉树的深度为:"<<tree.Tree_Depth(p)<<endl; BinTree tree2; BinNode *p2=tree2.Get_Root(); cout<<"_____复制二叉树_______"<<endl; p2=tree.Copy(p); cout<<"_____复制完成_____"<<endl; cout<<"复制后的树的先序遍历为:"; tree2.PreOrder_rec(p2); cout<<endl; cout<<"____交换二叉树左右子树____"<<endl; My_stack<BinNode *> s; tree2.Exchange(p2,s); cout<<"____交换完成____"<<endl; cout<<"交换后先序遍历为:"; tree2.PreOrder_rec(p2); cout<<endl; cout<<"二叉树的叶子结点数目为:"; int sum=tree2.Leaf_rec(p2); cout<<sum<<endl; tree2.Ancestor(p2,1); cout<<endl; if(tree2.Is_CompleteBInTree(p2)) cout<<"完全二叉树"<<endl; else cout<<"不是完全二叉树"<<endl; tree2.Counter(p2); cout<<"输出二叉树中所有从根节点出发到叶子结点的路径: "<<endl; stack<BinNode *> s1; tree.Out_Path(p,s1); return 0; }
例如输入: 5 3 2 1 0 0 0 4 0 0 8 6 0 7 0 0 9 0 0 后建立的一个二叉树呢 是这个样子的(图片所示,画的不好,可以看就行。。。)
输出结果呢 是这样的,里面加上了测试时间的一小段代码
二叉树为空 输入数据(0代表空):5 输入数据(0代表空):3 输入数据(0代表空):2 输入数据(0代表空):1 输入数据(0代表空):0 输入数据(0代表空):0 输入数据(0代表空):0 输入数据(0代表空):4 输入数据(0代表空):0 输入数据(0代表空):0 输入数据(0代表空):8 输入数据(0代表空):6 输入数据(0代表空):0 输入数据(0代表空):7 输入数据(0代表空):0 输入数据(0代表空):0 输入数据(0代表空):9 输入数据(0代表空):0 输入数据(0代表空):0 二叉树不空 先序遍历二叉树:5 3 2 1 4 8 6 7 9 中序遍历二叉树:1 2 3 4 5 6 7 8 9 后序遍历二叉树:1 2 4 3 7 6 9 8 5 按层次遍历二叉树:5 3 8 2 4 6 9 1 7 这段代码运行时间为:20ms 二叉树的深度为:4 _____复制二叉树_______ _____复制完成_____ 复制后的树的先序遍历为:5 3 2 1 4 8 6 7 9 ____交换二叉树左右子树____ ____交换完成____ 交换后先序遍历为:5 8 9 6 7 3 4 2 1 二叉树的叶子结点数目为:4 结点值为1的祖先为: 2 3 5 不是完全二叉树 将帮你比如统计每一层中不小于特定数字的结点总数并输出对应结点的值 输入你要作为比较标志的数字:3 第1层中不小于3的结点总数为:1个 具体是:5 第2层中不小于3的结点总数为:2个 具体是:8 3 第3层中不小于3的结点总数为:3个 具体是:9 6 4 第4层中不小于3的结点总数为:1个 具体是:7 输出二叉树中所有从根节点出发到叶子结点的路径: 5->3->2->1 5->3->4 5->8->6->7 5->8->9 Press any key to continue
今天发现的一个好东西 可以用system("pause"); 来加在你想要暂停的代码后面,就比如 我上面的程序中 我把这句话 加在 求祖先的那个函数里面 ,具体加在哪里看下面代码 加大号那里,加了那句以后是什么效果呢 ,看下面的运行结果
void Ancestor(BinNode *p,int d) { if(!p) { cout<<"二叉树空"<<endl; return ; } if(p->data==d) { cout<<"因为"<<d<<"是根节点的值,所以没有祖先"<<endl; return ; } else { My_stack<BinNode *> s; BinNode *t=p; while(t || !s.empty()) { while(t && t->data!=d) { //将t的tag置为0,压进栈,先从左边开始 t->tag=0; s.push(t); t=t->lchild; } if(t && t->data==d) { cout<<"结点值为"<<d<<"的祖先为:"<<endl; while(!s.empty()) { BinNode *temp=s.top(); s.pop(); cout<<temp->data<<" "; system("pause"); } return ; } else { //t为空且data!=d BinNode *temp=s.top(); s.pop(); while(!s.empty() && temp->tag==1) { temp=s.top(); s.pop(); } if(temp->tag!=1) { temp->tag=1; s.push(temp); t=temp->rchild; } }//end_else(t==NULL) }//end_while }//end_else(t!=0 && t->data!=d) }//end
下面多了 那个按任意键继续的提示 ,就是暂停了在那里后,可以继续开始的提示 这个用来找错误还是不错的 特别是循环很多的时候,指针很多的时候