///////////////////头文件:BST.h//////////////////////// #ifndef BST_H #define BST_H #include "StdAfx.h" #include<iostream> #include<stack> template<typename DataType> class BST { public: class Node { public: Node(int data=0):m_data(data),m_left(NULL),m_right(NULL) {} public: int m_data; Node* m_left; Node* m_right; }; typedef Node* NodePointer; public: BST(); bool empty() const; void insert(const DataType& item); void preordertrav(NodePointer root);//前序遍历(循环) void preordertravRec(NodePointer root);//前序遍历(递归) void midordertrav(NodePointer root);//中序遍历(循环) void midordertravRec(NodePointer root);//中序遍历(递归) void postordertrav(NodePointer root);//后序遍历(循环) void postordertravRec(NodePointer root);//后序遍历(递归) void static visit(Node* p);//输出相应的节点 public: Node* myroot;//根节点 }; template<typename DataType> inline BST<DataType>::BST():myroot(NULL) {} template<typename DataType> inline bool BST<DataType>::empty() const { return myroot==NULL; } #endif
1 #include "StdAfx.h" 2 #include"BST.h" 3 #include<iostream> 4 #include<stack> 5 using namespace std; 6 //通过insert建树 7 template<typename DataType> 8 void BST<DataType>::insert(const DataType& item) 9 { 10 BST<DataType>::NodePointer locptr=myroot,//记录可以插入的位置,从根节点开始 11 parent=NULL;//记录可以插入的位置的根节点 12 bool found=false;//表明item是否已经在BST中 13 while(!found&&locptr!=NULL)//查找可以插入的位置 14 {//在这里找到可以插入的位置是可插入的父节点,在这个父节点上插入 15 parent=locptr; 16 if(item<locptr->m_data)//比根节点小 17 locptr=locptr->m_left;//往左边继续找 18 else if(locptr->m_data<item)//比根节点大 19 locptr=locptr->m_right;//往右边继续找 20 else 21 found=true; 22 } 23 if(!found)//执行插入操作 24 { 25 locptr=new BST<DataType>::Node(item);//创建新节点 26 if(parent==NULL)//如果该开始是空树,则第一个插入的就是根节点 27 myroot=locptr; 28 else if(item<parent->m_data) 29 parent->m_left=locptr; 30 else 31 parent->m_right=locptr; 32 } 33 else 34 cout<<"Item already in the tree"; 35 } 36 //前序遍历,循环实现(中左右) 37 template<typename DataType> 38 void BST<DataType>::preordertrav(NodePointer root) 39 { 40 if(root==NULL) 41 return ; 42 stack<BST<DataType>::NodePointer>ss;//用来存放遍历的节点,注意这里的节点的类型 43 Node* curr=root; 44 while(!ss.empty()||curr!=NULL) 45 { 46 while(curr!=NULL) 47 { 48 visit(curr);//第一个访问根节点 49 ss.push(curr);//保存根节点 50 curr=curr->m_left;//然后是左节点 51 } 52 Node* p=ss.top();//最左边的左节点 53 ss.pop();//删除,因为它已经遍历了 54 curr=p->m_right;//但是删除之后还必须考察它的右节点是否存在 55 } 56 } 57 //前序遍历,递归实现 58 template<typename DataType> 59 void BST<DataType>::preordertravRec(NodePointer root) 60 { 61 if(root==NULL) 62 { 63 //cout<<"错误的输入!"<<endl; 64 return ; 65 } 66 visit(root);//访问根节点 67 preordertravRec(root->m_left); 68 preordertravRec(root->m_right); 69 } 70 71 //中序遍历,循环方式实现 72 template<typename DataType> 73 void BST<DataType>::midordertrav(NodePointer root) 74 { 75 if(NULL==root) 76 return; 77 stack<BST<DataType>::NodePointer>ss;//定义一个栈来存储遍历的路径 78 BST<DataType>::NodePointer curr=root;//定义一个当前的节点来作为临时变量 79 while(!ss.empty()||curr!=NULL) 80 { 81 while(curr!=NULL)//先遍历左子树 82 { 83 ss.push(curr);//压栈 84 curr=curr->m_left; 85 } 86 //此时最左边的路径已经遍历完了,现在开始返回,记住:也要把最左边的叶子节点当作根节点来看待 87 BST<DataType>::NodePointer p=ss.top();//取出最左边的节点 88 visit(p);//如果该节点没有左节点就输出该节点 89 ss.pop();//删除该节点,因为他已经遍历了。 90 curr=p->m_right;//由于该节点没有左节点,但是不知道右节点是否存在,因此需要仅需判断右节点 91 } 92 } 93 //中序遍历,递归实现 94 template<typename DataType> 95 void BST<DataType>::midordertravRec(NodePointer root) 96 { 97 if(root==NULL) 98 { 99 //cout<<"错误的输入!"<<endl; 100 return ; 101 } 102 midordertravRec(root->m_left); 103 visit(root); 104 midordertravRec(root->m_right); 105 106 } 107 108 //后序遍历,循环实现 109 template<typename DataType> 110 void BST<DataType>::postordertrav(NodePointer root) 111 { 112 if(root==NULL) 113 return ; 114 stack<NodePointer>ss; 115 BST<DataType>::NodePointer curr=root;//定义一个当前的节点来作为临时变量 116 BST<DataType>::NodePointer last=NULL;//定义一个节点来表示之前访问的节点 117 while(curr!=NULL||!ss.empty()) 118 { 119 120 while(curr!=NULL) 121 { 122 ss.push(curr);//压栈 123 curr=curr->m_left; 124 } 125 curr=ss.top();//最左边的节点 126 127 //其访问方式是:左节点——>根节点(这时并不访问)——>右节点——>根节点(这时才访问) 128 //这个访问节点的状态转换都是通过判断当前节点的右节点是否存在来实现转换。 129 130 //如果当前节点的右节点已经访问过或者没有右节点 131 if(curr->m_right==NULL||last==curr->m_right) 132 { 133 visit(curr);//访问当前节点 134 last=curr;//记录上次访问过的节点 135 ss.pop();//删除左节点 136 curr=NULL;//下次访问根节点 137 138 } 139 else 140 { 141 //否则将右节点压栈 142 curr=curr->m_right; 143 } 144 } 145 } 146 //后序遍历,递归实现 147 template<typename DataType> 148 void BST<DataType>::postordertravRec(NodePointer root) 149 { 150 if(root==NULL) 151 return ; 152 postordertravRec(root->m_left); 153 postordertravRec(root->m_right); 154 visit(root); 155 } 156 157 template<typename DataType> 158 void BST<DataType>::visit(Node* p) 159 { 160 if(p==NULL) 161 return ; 162 cout<<p->m_data<<" "; 163 }
////////////测试代码////////////////////
1 // MidOrderTrav.cpp : 定义控制台应用程序的入口点。 2 //二叉树的中序遍历 3 4 #include "stdafx.h" 5 #include<iostream> 6 7 //#include"BST.h" 8 #include"BST2.cpp" 9 10 using namespace std; 11 12 //template<typename DataType> 13 void ad(BST<int>::Node* root) 14 { 15 if(root==NULL) 16 return ; 17 stack<BST<int>::NodePointer>ss; 18 BST<int>::NodePointer curr=root;//定义一个当前的节点来作为临时变量 19 BST<int>::NodePointer last=NULL;//定义一个节点来表示之前访问的节点 20 while(curr!=NULL||!ss.empty()) 21 { 22 23 while(curr!=NULL) 24 { 25 ss.push(curr);//压栈 26 curr=curr->m_left; 27 } 28 curr=ss.top();//最左边的节点 29 30 //其访问方式是:左节点——>根节点(这时并不访问)——>右节点——>根节点(这时才访问) 31 //这个访问节点的状态转换都是通过判断当前节点的右节点是否存在来实现转换。 32 33 //如果当前节点的右节点已经访问过或者没有右节点 34 if(curr->m_right==NULL||last==curr->m_right) 35 { 36 BST<int>::visit(curr);//访问当前节点 37 last=curr;//记录上次访问过的节点 38 ss.pop();//删除左节点 39 curr=NULL;//下次访问根节点,并判断右节点 40 } 41 else 42 { 43 //否则将右节点压栈 44 curr=curr->m_right; 45 } 46 } 47 } 48 49 //2、题目:求二叉树的深度,利用遍历的方式,每一次遍历一个节点之后,等于它左右子树较大的深度加1 50 int TreeDepth(BST<int>::Node* pRoot) 51 { 52 if(pRoot==NULL) 53 return 0; 54 int left=TreeDepth(pRoot->m_left); 55 int right=TreeDepth(pRoot->m_right); 56 57 return left>right?left+1:right+1; 58 } 59 //3、判断是否是平衡二叉树 60 bool IsBalance(BST<int>::Node* pRoot) 61 { 62 //如果一个二叉树的每一个节点的左右子树的深度差小于等于1就是平衡树 63 //因此,我们可以求出根节点的左右子树的深度 64 if(pRoot==NULL) 65 return false; 66 int left=TreeDepth(pRoot->m_left);//求出左子树的深度 67 int right=TreeDepth(pRoot->m_right);//求出右子树的深度 68 if(left-right<=1&&left-right>=-1)//左右子树的深度差 69 return true; 70 return false; 71 } 72 73 74 75 int main() 76 { 77 cout<<"请输入一组数:"<<endl; 78 int a; 79 BST<int>bst; 80 while(cin>>a) 81 { 82 bst.insert(a); 83 } 84 85 cout<<"前序遍历(循环):"<<endl; 86 bst.preordertrav(bst.myroot);//前序遍历(循环) 87 cout<<endl; 88 cout<<"前序遍历(递归):"<<endl; 89 bst.preordertravRec(bst.myroot);//前序遍历(递归) 90 cout<<endl; 91 cout<<"中序遍历(循环):"<<endl; 92 bst.midordertrav(bst.myroot);//中序遍历(循环) 93 cout<<endl; 94 cout<<"中序遍历(递归):"<<endl; 95 bst.midordertravRec(bst.myroot);//中序遍历(递归) 96 cout<<endl; 97 cout<<"后序遍历(循环):"<<endl; 98 //ad(bst.myroot); 99 bst.postordertrav(bst.myroot);//后序遍历(循环) 100 cout<<endl; 101 cout<<"后序遍历(递归):"<<endl; 102 bst.postordertravRec(bst.myroot); 103 cout<<endl; 104 105 106 cout<<"求二叉树的深度h:"<<endl; 107 cout<<TreeDepth(bst.myroot)<<endl; 108 109 110 cout<<"判断一颗二叉树是否是平衡树:"<<endl; 111 if(IsBalance(bst.myroot)) 112 cout<<"这棵树是平衡二叉树"<<endl; 113 else 114 cout<<"这棵树不是平衡二叉树"<<endl; 115 116 117 return 0; 118 }
二叉树的三种遍历方式的循环和递归的实现方式
时间: 2024-12-26 17:32:48