1、先序遍歷
基本思想:
1>首先定義一個棧,每遇到一個節點,就對其數據進行訪問;然後將其入棧,將當前節點的左孩子賦給它,循環此過程,直到最左節點被訪問並被壓入棧中。
2>出循環後用臨時變量保存棧頂節點,然後對棧頂節點進行出棧操作,到此說明當前節點以及其左子樹已被訪問過了。
3>將臨時變量的右孩子賦給當前節點,用子問題的方式去訪問其右子樹。
- void preorderR(Node* root)//先序遍歷打印樹的各個節點
- {
- Node* cur = root;
- stack<Node*> s;
- while (!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
- {
- while(cur)//先序遍歷,遇到樹根節點直接訪問數據並將其壓棧
- {
- cout<<cur->_value<<" ";
- s.push(cur);
- cur = cur->_lchild;
- }
- Node* top = s.top();//取出棧頂元素,到此說明此節點以及其左子樹已經訪問過了
- s.pop();
- cur = top->_rchild;//以子問題的方式去訪問右子樹
- }
- cout<<endl;
- }
2、中序遍歷
基本思想:
1>首先定義一個棧,每遇到一個節點,就將其入棧,將當前節點的左孩子賦給它,循環此過程,直到最左節點將其壓入棧中。
2>出循環後用臨時變量保存棧頂節點,訪問棧頂節點的數據,然後對棧頂節點進行出棧操作,到此說明當前節點的左子樹以及當前節點已被訪問過了。
3>將臨時變量的右孩子賦給當前節點,用子問題的方式去訪問其右子樹。
- void inorderR(Node* root)//中序遍歷打印樹的各個節點
- {
- Node* cur = root;
- stack<Node*> s;
- while(!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
- {
- while(cur)//中序遍歷,遇到樹根節點直接將其壓棧
- {
- s.push(cur);
- cur = cur->_lchild;
- }
- Node* top = s.top();//取出棧頂元素,到此說明此節點的左子樹已經訪問過了
- cout<<top->_value<<" ";//訪問棧頂元素(即根節點)
- s.pop();
- cur = top->_rchild;//以子問題的方式去訪問右子樹
- }
- cout<<endl;
- }
3、後序遍歷
1>首先定義一個棧和一個記錄上一個被訪問節點的變量,每遇到一個節點,就對其數據進行訪問;然後將其入棧,將當前節點的左孩子賦給它,循環此過程,直到最左節點被訪問並被壓入棧中。
2>出循環後用臨時變量保存棧頂元素,只有當前節點的右子樹爲空或者其右子樹已經訪問過時,才能對當前節點進行訪問,同時將棧頂元素出棧
3>將臨時變量的右孩子賦給當前節點,用子問題的方式去訪問其右子樹。
- void postorderR(Node* root)//後序遍歷打印樹的各個節點
- {
- Node* cur = root;
- Node* prev = NULL;//上一個訪問過的數據
- stack<Node*> s;
- while(!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
- {
- //後序遍歷,遇到樹根節點直接將其壓棧
- while(cur)
- {
- s.push(cur);
- cur = cur->_lchild;
- }
- Node* top = s.top();//取棧頂元素,但不一定能訪問
- //當節點右子樹爲空或已經訪問過時對其直接進行訪問
- if (top->_rchild==NULL || top->_rchild==prev)
- {
- cout<<top->_value<<" ";
- prev = top;//將prev更新爲已經訪問的節點
- s.pop();
- }
- else//以子問題的方式去訪問右子樹
- {
- cur = top->_rchild;
- }
- }
- cout<<endl;
- }
完整的代碼及測試:
- #include <iostream>
- #include <cassert>
- #include <queue>
- #include <stack>
- using namespace std;
- template <class T>
- struct TreeNode
- {
- TreeNode(const T& value = T())
- :_value(value)
- ,_lchild(0)
- ,_rchild(0)
- {}
- T _value;//節點的值
- TreeNode<T>* _lchild;//左孩子
- TreeNode<T>* _rchild;//右孩子
- };
- template <class T>
- class BinaryTree
- {
- public:
- typedef TreeNode<T> Node;
- BinaryTree()//無參構造函數
- :_root(NULL)
- {}
- BinaryTree(const T* a,size_t size,const T& invalid)//構造函數
- {
- assert(a);
- size_t index = 0;
- _root = CreatTree(a,size,invalid,index);
- }
- BinaryTree(const BinaryTree<T>& b)//拷貝構造
- {
- _root = Copy(b._root);
- }
- //現代寫法的賦值運算符重載1
- BinaryTree& operator=(const BinaryTree<T>& b)
- {
- if (this != &b)
- {
- Node* tmp = Copy(b._root);
- Destroy(_root) ;
- _root = tmp;
- //swap(_root,tmp);
- }
- return *this;
- }
- ////現代寫法的賦值運算符重載2
- //BinaryTree& operator=(BinaryTree<T> b)
- //{
- // swap(b._root,_root);
- // return *this;
- //}
- ~BinaryTree()//析構
- {
- if (NULL != _root)
- {
- Destroy(_root);
- _root = NULL;
- }
- }
- void PreOrder()//先序遍歷打印樹的各個節點
- {
- cout<<"先序遍歷:";
- preorderR(_root);
- cout<<endl;
- }
- void InOrder()//中序遍歷打印樹的各個節點
- {
- cout<<"中序遍歷:";
- inorderR(_root);
- cout<<endl;
- }
- void PostOrder()//後序遍歷打印樹的各個節點
- {
- cout<<"後序遍歷:";
- postorderR(_root);
- cout<<endl;
- }
- void LevelOrder()//層序遍歷打印樹的各個節點
- {
- cout<<"層序遍歷:";
- levelorder(_root);
- cout<<endl;
- }
- size_t Size()//求樹中的節點個數
- {
- cout<<"size:";
- return size(_root);
- }
- size_t Depth()//求樹的深度
- {
- cout<<"depth:";
- return depth(_root);
- }
- size_t GetLeafSize()
- {
- cout<<"leaf_size:";
- return getleafsize(_root);
- }
- size_t GetKLevelSize(size_t k)//樹中第k層的節點個數
- {
- cout<<k<<"_level_size:";
- return getklevelsize(_root,k);
- }
- protected:
- //按照先序遍歷遞歸建樹
- Node* CreatTree(const T* a,size_t size,const T& invalid,size_t& index)//注意index的傳值方式
- {
- assert(a);
- Node* root = NULL;
- if (a[index] != invalid && index < size)//按先序遍歷建樹
- {
- root = new Node(a[index]);
- root->_lchild = CreatTree(a,size,invalid,++index);
- root->_rchild = CreatTree(a,size,invalid,++index);
- }
- return root;
- }
- //拷貝對象
- Node* Copy(Node* root)
- {
- Node* tmp = NULL;
- if(root)
- {
- tmp = new Node(root->_value);
- tmp->_lchild = Copy(root->_lchild);
- tmp->_rchild = Copy(root->_rchild);
- }
- return tmp;
- }
- //釋放空間
- void Destroy(Node*& root)
- {
- if(root)//用後序遍歷方式釋放空間
- {
- Destroy(root->_rchild);
- Destroy(root->_lchild);
- delete root;
- root = NULL;
- }
- }
- void preorderR(Node* root)//先序遍歷打印樹的各個節點
- {
- Node* cur = root;
- stack<Node*> s;
- while (!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
- {
- while(cur)//先序遍歷,遇到樹根節點直接訪問數據並將其壓棧
- {
- cout<<cur->_value<<" ";
- s.push(cur);
- cur = cur->_lchild;
- }
- Node* top = s.top();//取出棧頂元素,到此說明此節點以及其左子樹已經訪問過了
- s.pop();
- cur = top->_rchild;//以子問題的方式去訪問右子樹
- }
- cout<<endl;
- }
- void inorderR(Node* root)//中序遍歷打印樹的各個節點
- {
- Node* cur = root;
- stack<Node*> s;
- while(!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
- {
- while(cur)//中序遍歷,遇到樹根節點直接將其壓棧
- {
- s.push(cur);
- cur = cur->_lchild;
- }
- Node* top = s.top();//取出棧頂元素,到此說明此節點的左子樹已經訪問過了
- cout<<top->_value<<" ";//訪問棧頂元素(即根節點)
- s.pop();
- cur = top->_rchild;//以子問題的方式去訪問右子樹
- }
- cout<<endl;
- }
- void postorderR(Node* root)//後序遍歷打印樹的各個節點
- {
- Node* cur = root;
- Node* prev = NULL;//上一個訪問過的數據
- stack<Node*> s;
- while(!s.empty() || cur)//只要當前節點和棧不同時爲空,就說明樹沒遍歷完
- {
- //後序遍歷,遇到樹根節點直接將其壓棧
- while(cur)
- {
- s.push(cur);
- cur = cur->_lchild;
- }
- Node* top = s.top();//取棧頂元素,但不一定能訪問
- //當節點右子樹爲空或已經訪問過時對其直接進行訪問
- if (top->_rchild==NULL || top->_rchild==prev)
- {
- cout<<top->_value<<" ";
- prev = top;//將prev更新爲已經訪問的節點
- s.pop();
- }
- else//以子問題的方式去訪問右子樹
- {
- cur = top->_rchild;
- }
- }
- cout<<endl;
- }
- void levelorder(Node* root)//層序遍歷打印樹的各個節點
- {
- queue<Node*> q;
- if (root)
- {
- q.push(root);//將根節點插進隊列
- }
- while(!q.empty())
- {
- Node* front = q.front();
- q.pop();
- cout<<front->_value<<" ";
- if (front->_lchild)
- {
- q.push(front->_lchild);
- }
- if (front->_rchild)
- {
- q.push(front->_rchild);
- }
- }
- }
- size_t size(Node* root)//求樹中的節點個數
- {
- size_t count = 0;
- if (NULL == root)
- {
- count = 0;
- }
- else
- {
- //當前節點 = 左子樹節點 + 右子樹節點 + 1
- count = size(root->_lchild) + size(root->_rchild)+ 1;
- }
- return count;
- }
- size_t depth(Node* root)//求樹的深度
- {
- if (NULL == root)
- {
- return 0;
- }
- else
- {
- return depth(root->_lchild)>depth(root->_rchild)?
- (depth(root->_lchild)+1):(depth(root->_rchild)+1);
- }
- }
- size_t getleafsize(Node* root)//求葉節點的個數
- {
- if (NULL == root)//空樹
- {
- return 0;
- }
- if (NULL == root->_lchild && NULL == root->_rchild)//左葉節點右節點均爲空,即
- {
- return 1;
- }
- else//左子樹的葉節點+右子樹的葉節點
- {
- return getleafsize(root->_lchild)+getleafsize(root->_rchild);
- }
- }
- size_t getklevelsize(Node* root,size_t k)//樹中第k層的節點個數
- {
- assert(k>0);
- size_t count = 0;
- if (NULL == root)
- {
- return 0;
- }
- if (k == 1)
- {
- count++;
- }
- else
- {
- count = getklevelsize(root->_lchild,k-1)
- + getklevelsize(root->_rchild,k-1);
- }
- return count;
- }
- protected:
- Node* _root;//根節點
- };
- void TestBinaryTree()
- {
- int arr[] = {1, 2, 3, '#', '#', 4, '#' , '#', 5, 6,'#','#','#'};
- size_t size = sizeof(arr)/sizeof(arr[0]);
- BinaryTree<int> bt(arr,size,'#');
- BinaryTree<int> b1(bt);
- BinaryTree<int> b2;
- b2 = bt;
- b2.PreOrder();
- b2.InOrder();
- b2.PostOrder();
- b2.LevelOrder();
- cout<<b2.Size()<<endl;
- cout<<b2.Depth()<<endl;
- cout<<b2.GetLeafSize()<<endl;
- cout<<b2.GetKLevelSize(1)<<endl;
- cout<<b2.GetKLevelSize(2)<<endl;
- cout<<b2.GetKLevelSize(3)<<endl;
- }
- int main()
- {
- TestBinaryTree();
- system("pause");
- return 0;
- }