第五章 树和二叉树 笔记 完结
PS:对于递归实现的前序,中序,后序算法,无非是在递归时,根的访问位置不同而已,代码内容几乎相似。非递归算法实现时,当root指针或栈非空时,先循环考虑root是否为否执行相应的操作,对于栈判断是否为空,进行root的转换。前序,后序,中序的非递归算法区别无非是每棵树的根节点的输出时机不同而已,具体实现大同小异。
1.二叉树的前序遍历-------------------非递归实现算法(伪代码)和递归实现
非递归实现伪代码:
1.栈s初始化(空栈); 2.循环直到root为空且栈s为空 2.1 当root不空时循环 2.1.1 输出root->data; 2.1.2 将指针root的值保存到栈中; 2.1.3 继续遍历root的左子树(root=root->lchild) 2.2 如果栈s不空,则 2.2.1 将栈顶元素弹出至root(root=s.pop()); 2.2.2 准备遍历root的右子树(root=root->rchild);
代码:
template <class T> void BiTree::PreOrder(BiNode<T> *root) { SeqStack<BiNode<T> *> s; while (root!=NULL | | !s.empty()) { while (root!= NULL) { cout<<root->data; s.push=root; root=root->lchild; } if (!s.empty()) { root=s.pop(); root=root->rchild; } } }
递归实现:
template <class T> void BiTree::PreOrder(BiNode<T> *root) { if (root ==NULL) return; else { cout<<root->data; PreOrder( root->lchild ); PreOrder( root->rchild); } }
2.二叉树的建立伪代码:
1.按前序扩展遍历序列输入输入节点的值
2.如果输入节点之为“#”,则建立一棵空的子树
3.否则,根结点申请空间,将输入值写入数据域中,
4.以相同方法的创建根节点的左子树
5.以相同的方法创建根节点的右子树
递归方法
代码:
template <class T> BiTree ::BiTree(){ root=creat(); } template <class T> BiNode<T> * BiTree ::Creat(){ BiNode<T> *root; char ch; cin>>ch; if (ch=='# ') root=NULL; else { root=new BiNode<T>; root->data=ch; root->lchild=creat(); root->rchild= creat(); } return root }
3.
中序遍历---------递归算法
template <class T> void BiTree::InOrder (BiNode<T> *root) { if (root==NULL) return; else { InOrder(root->lchild); cout<<root->data; InOrder(root->rchild); } }
中序遍历--------非递归算法(伪代码):
1.栈s初始化(空栈); 2.循环直到root为空且栈s为空 2.1 当root不空时循环 2.1.1 将指针root的值保存到栈中; 2.1.2 继续遍历root的左子树(root=root->lchild) 2.2 如果栈s不空,则 2.2.1 将栈顶元素弹出至root(root=s.pop()); 2.2.2 输出root->data; 2.2.3 准备遍历root的右子树(root=root->rchild);
代码:
template <class T> void BiTree::InOrderwithoutD(BiNode<T> *root) { stack< BiNode<T> * > aStack; while (!aStack.empty() || root) { while (root) { aStack.push(root); root = root->lchild; } if (!aStack.empty()) { root = aStack.top(); aStack.pop(); cout << root->data; root = root->rchild; } } }
4.
后序遍历-----------递归算法
template <class T> void BiTree::PostOrder(BiNode<T> *root) { if (root==NULL) return; else { PostOrder(root->lchild); PostOrder(root->rchild); cout<<root->data; } }
后序遍历的非递归实现:一种你叫巧妙的方法
分析:对于每一个节点压入栈两次,再循环体中,每次弹出一个赋值给p,若p仍和栈的栈顶元素相似,说明它的孩子们还没有访问过,将孩子们加入栈中,否则访问p。也就是第一次弹出将p的孩子们压入栈,第二次弹出访问p。
template<class T> ///后序遍历 void BiTree<T>::PostOrder(BiNode<T> *root) { stack<BiNode<T>* >astack; BiNode<T> *p=root; astack.push(p); astack.push(p); while(!astack.empty()) { p=astack.top(); astack.pop(); if(!astack.empty()&&p==astack.top()) { if(p->rchild) astack.push(p->rchild), astack.push(p->rchild); if(p->lchild) astack.push(p->lchild), astack.push(p->lchild); } else { cout<<p->data; } } }
通过递归方式建树并测试:
代码:
#include<bits/stdc++.h> using namespace std; template <class T> struct BiNode { T data; BiNode<T> *lchild, *rchild; }; template <class T> class BiTree { public: BiTree(){Creat(root);} void PreOrder() { PreOrder(root); } void InOrder() { InOrder(root); } void PostOrder() { PostOrder(root);} void LevelOrder(){LevelOrder(root);} private: BiNode<T> *root; void Creat(BiNode<T> *& root); void Release(BiNode<T> *root); void PreOrder(BiNode<T> *root); void InOrder(BiNode<T> *root); void PostOrder(BiNode<T> *root); void LevelOrder(BiNode<T> *root); }; template<class T> ///建立二叉树 void BiTree<T>::Creat(BiNode<T>*&root) { T ch; cin >> ch; if (ch == '#') root = NULL; else { root = new BiNode<T>; root->data = ch; Creat(root->lchild); Creat(root->rchild); } } template<class T> ///前序遍历 void BiTree<T>::PreOrder(BiNode<T> *root) { if (root == NULL) return; else { cout << root->data; PreOrder(root->lchild); PreOrder(root->rchild); } } template<class T> ///中序遍历 void BiTree<T>::InOrder(BiNode<T> *root) { if (root == NULL) return; else { InOrder(root->lchild); cout << root->data; InOrder(root->rchild); } } template<class T> ///后序遍历 void BiTree<T>::PostOrder(BiNode<T> *root) { if (root == NULL) return; else { PostOrder(root->lchild); PostOrder(root->rchild); cout << root->data ; } } template<class T> void BiTree<T>::Release(BiNode<T>* root) { if (root != NULL) { Release(root->lchild); Release(root->rchild); delete root; } } template<class T> ///层序遍历 void BiTree<T>::LevelOrder(BiNode<T> *root) { queue<BiNode<T> *>aqueue; if(root)///当根节点不为空 { aqueue.push(root); while(!aqueue.empty()) { root=aqueue.front(); aqueue.pop(); cout<<root->data; if(root->lchild) aqueue.push(root->lchild); if(root->rchild) aqueue.push(root->rchild); } } } int main()///在主函数中测试前、中、后、层序遍历 { char s; while (true) { BiTree<char> a; cin>>s; a.PreOrder(); cout << endl; a.InOrder(); cout << endl; a.PostOrder(); cout << endl; a.LevelOrder(); cout<<endl; } return 0; }
非递归实现二叉树的前、中、后序访问并测试代码:
#include<bits/stdc++.h> using namespace std; template <class T> struct BiNode { T data; BiNode<T> *lchild, *rchild; }; template <class T> class BiTree { public: BiTree(){Creat(root);} ~BiTree(){Release(root);} void PreOrder() { PreOrder(root); } void InOrder() { InOrder(root); } void PostOrder() { PostOrder(root);} void LevelOrder(){LevelOrder(root);} private: BiNode<T> *root; void Creat(BiNode<T> *& root); void Release(BiNode<T> *root); void PreOrder(BiNode<T> *root); void InOrder(BiNode<T> *root); void PostOrder(BiNode<T> *root); void LevelOrder(BiNode<T> *root); }; template<class T> ///建立二叉树 void BiTree<T>::Creat(BiNode<T>*&root) { T ch; cin >> ch; if (ch == '#') root = NULL; else { root = new BiNode<T>; root->data = ch; Creat(root->lchild); Creat(root->rchild); } } /*非递归实现前序遍历时,当根节点和栈都不为空时,先访问当前的根节点,倘若不为空,输出当前节点的值将当前的 根节点入栈 ,继续遍历当前节点的左孩子,否则若栈不为空,将节点出栈,访问它的右孩子,直到根节点和栈都为空*/ template<class T> ///前序遍历 void BiTree<T>::PreOrder(BiNode<T> *root) { stack<BiNode<T> *>astack; while(root||!astack.empty()) { while(root) { cout<<root->data; astack.push(root); root=root->lchild; } if(!astack.empty()) { root=astack.top(); astack.pop(); root=root->rchild; } } } template<class T> ///中序遍历 void BiTree<T>::InOrder(BiNode<T> *root) { stack<BiNode<T>* >astack; while(root||!astack.empty()) { while(root) { astack.push(root); root=root->lchild; } if(!astack.empty()) { root=astack.top(); cout<<root->data; astack.pop(); root=root->rchild; } } } /*对于每个节点,都压入两遍,在循环体中,每次弹出一个节点赋给p, 如果p仍然等于栈的头结点,说明p的孩子们还没有被操作过, 应该把它的孩子们加入栈中,否则,访问p。也就是说,第一次弹出, 将p的孩子压入栈中,第二次弹出,访问p。*/ template<class T> ///后序遍历 void BiTree<T>::PostOrder(BiNode<T> *root) { stack<BiNode<T>* >astack; BiNode<T> *p=root; astack.push(p); astack.push(p); while(!astack.empty()) { p=astack.top(); astack.pop(); if(!astack.empty()&&p==astack.top()) { if(p->rchild) astack.push(p->rchild), astack.push(p->rchild); if(p->lchild) astack.push(p->lchild), astack.push(p->lchild); } else { cout<<p->data; } } } template<class T> void BiTree<T>::Release(BiNode<T>* root) { if (root != NULL) { Release(root->lchild); Release(root->rchild); delete root; } } template<class T> ///层序遍历 void BiTree<T>::LevelOrder(BiNode<T> *root) { queue<BiNode<T> *>aqueue; if(root)///当根节点不为空 { aqueue.push(root); while(!aqueue.empty()) { root=aqueue.front(); aqueue.pop(); cout<<root->data; if(root->lchild) aqueue.push(root->lchild); if(root->rchild) aqueue.push(root->rchild); } } } int main() { char s; while (true) { BiTree<char> a; cin>>s; a.PreOrder(); cout << endl; a.InOrder(); cout << endl; a.PostOrder(); cout << endl; a.LevelOrder(); cout<<endl; } return 0; }
关于树的节点数、叶子节点数、高度、交换左右子树算法的实现及检验:
#include <bits/stdc++.h> using namespace std; struct BiNode { char data; BiNode *lchild,*rchild; }; class BiTree { public: int number; int leave; BiTree(); void PreOrder(){PreOrder(root);} void countNode(){countNode(root);} void countLeaf(){countLeaf(root);} int height(){return height(root);} void swapTree(){swapTree(root);} private: BiNode *root; BiNode *creat(); void PreOrder(BiNode *root);//前序遍历 void countNode(BiNode *root); void countLeaf(BiNode *root); int height(BiNode *root); void swapTree(BiNode *root); }; BiTree ::BiTree(){ root=creat(); } BiNode * BiTree ::creat(){ BiNode *root; char ch; cin>>ch; if (ch=='#') root=NULL; else { root=new BiNode; root->data=ch; root->lchild=creat(); root->rchild= creat(); } return root; } void BiTree::countNode(BiNode *root) {///统计节点数 if (root ==NULL) return; else { countNode(root->lchild); number++; countNode(root->rchild); } } void BiTree::countLeaf(BiNode *root) {///统计叶子节点数 if (root ==NULL) return; else { if(root->lchild==NULL&&root->rchild==NULL){ leave++; } countLeaf(root->lchild); countLeaf(root->rchild); } } int BiTree::height(BiNode *root) {///统计树的高度 int lheight=0,rheight=0; if(root){ lheight=height(root->lchild); rheight=height(root->rchild); if(lheight>rheight) return lheight+1; else return rheight+1; } else return 0; } void BiTree::swapTree(BiNode *root)///左后树交换 { BiNode *temp; if(root){ temp=root->lchild; root->lchild=root->rchild; root->rchild=temp; swapTree(root->lchild); swapTree(root->rchild); } } void BiTree::PreOrder(BiNode *root) { if (root ==NULL) return; else { cout<<root->data; PreOrder(root->lchild); PreOrder(root->rchild); } } int main() { char ch='Y'; while(ch=='Y'){ BiTree bt; bt.number=0; bt.countNode(); cout<<bt.number<<endl; bt.leave=0; bt.countLeaf(); cout<<bt.leave<<endl; int h=0; h=bt.height(); cout<<h<<endl; bt.swapTree(); bt.PreOrder(); cout<<endl; cin>>ch; } return 0; }
线索二叉树的实现:
enum flag{Child,Thread}; template<class T> struct ThrNode { T data; ThrNode<T> *lchild,*rchild; flag ltag,rtag; }; template<class T> class InThrBiTree{ public: InThrBiTree(){this->root=Creat();ThrBiTree(root);} ~InThrBiTree(); ThrNode<T>*Next(ThrNode<T> *p); void InOrder(ThrNode<T> *root); ThrNode<T> *pre; private: ThrNode<T> *root; ThrNode<T> * Creat(); void ThrBiTree(ThrNode<T> *root); }; template <class T> ThrNode<T>* InThrBiTree<T>::Creat( ){ ThrNode<T> *root; T ch; cout<<"请输入创建一棵二叉树的结点数据"<<endl; cin>>ch; if (ch=="#") root = NULL; else{ root=new ThrNode<T>; root->data = ch; root->ltag = Child; root->rtag = Child; root->lchild = Creat( ); root->rchild = Creat( ); } return root; } template<class T> void InThrBiTree<T>::ThrBiTree(ThrNode<T> *root)///递归实现线索二叉树 { if(root==NULL) return; else { if(!root->lchid) { root->lrag=Thread; root->lchild=pre; } } if(!root->rchild) root->rtag=Thread; if(!pre) { if(pre->rtag==Thread) { pre->rchild=root; } } pre==root; ThrBiTree(root->rchild); } template<class T> ThrNode<T>* InThrBiTree<T>::Next(ThrNode<T> *p) { ThrNode<T>*q;///要查找的P的后继 if(p->rtag==Thread) q=p->rchild; else { q=p->rchild; while(q->ltag==Child) { q=q->lchild; } } return q; } template<class T> void InThrBiTree<T>::InOrder(ThrNode<T> *root) { ThrNode<T> *p=root; if(root==NULL) return; while(p->ltag==Child) {p=p->lchild;cout<<p->data<<" ";} while(!p->rchild) { p=Next(p); cout<<p->data<<" "; } cout<<endl; }