理论基础 —— 二叉树 —— 线索链表
【概述】
對于一個有 n 個結點的二叉鏈表,每個結點指向左右孩子的兩個指針域,故共有 2n 個指針域,而 n 個結點的二叉樹共有 n-1 條分支,即存在 2n-(n-1)=n+1 個空指針域,白白浪費了資源。
另一方面,在二叉鏈表上,只能知道每個結點的左右孩子結點的地址,而不知道某個結點的前驅和后繼,要想知道,必須對二叉樹進行遍歷,以后每次想要知道時,都要遍歷一次,這無疑浪費了時間。
綜合以上兩個方面,可以考慮利用空地址,存放指向結點在某種遍歷次序下的前驅與后繼,將指向前驅與后繼的指針稱為線索,加上線索的二叉鏈表稱為線索鏈表,相應的二叉樹就稱為線索二叉樹。
【實現類】
線索化的實質就是將二叉鏈表中的空指針改為指向前驅或后繼的線索,因此其存儲結構相較于二叉鏈表有了更改
typedef enum{link,thread} Tag;//link=0表示指向左右孩子指針,thead=1表示指向前驅或后繼的線索 template<class T> struct Node{T data;//數據域Node<T> *lchild,rchild;//指針域Tag ltag,rtag;//標志域 };對二叉樹以某種次序遍歷使其變為線索二叉樹的過程稱為線索化,由于二叉樹的遍歷分為前序、中序、后序、層序四種,那么相應的,在建立線索二叉樹時,依據遍歷次序的不同,也同樣分為四種:
- 前序線索二叉樹
- 中序線索二叉樹
- 后序線索二叉樹
- 層序線索二叉樹
以上四種線索二叉樹只是在線索化時的順序有所不同,以下以中序線索二叉樹為例
template<class T> class ThreadTree{ public:ThreadTree();//構造函數,建立中序線索鏈表~ThreadTree();//析構函數,釋放各結點空間Node<T> * findNext(Node<T> *bt);//查找結點bt的后繼void inOrder();//中序遍歷 private:Node<T> *root;//指向線索鏈表的頭指針Node<T> * creat(Node<T> *bt);//構造函數調用void inThread(Node<T> *bt,Node<T> *pre);//構造函數調用 };【構造函數】
構造函數的功能是建立一個中序線索鏈表,實質上就是將二叉樹中的空指針改為指向前驅或后繼的線索,而前驅或后繼信息只有在遍歷該二叉樹時才能得到,因此建立線索鏈表應先建立一個二叉鏈表,然后在遍歷的過程中修改空指針建立線索鏈表。
template<class T> ThreadTree<T>::ThreadTree(){//構造函數root=creat(root);//建立帶線索標志的二叉鏈表Node<T> *pre=NULL;//當前訪問結點的前驅結點inThread(root,pre);//遍歷二叉鏈表,建立線索 } template<class T> Node<T>* ThreadTree<T>::creat(Node<T> *bt){//建立帶線索標志的二叉鏈表char ch;cin>>ch;if(ch=='#')//生成空樹bt=NULL;else{bt=new Node<T>;bt->data=ch;bt->ltag=link;//左標志bt->rtag=link;//右標志bt->lchild=creat(bt->lchild);//遞歸建立左子樹bt->rchild=creat(bt->rchild);//遞歸建立右子樹} }template<class T> void ThreadTree<T>::inThread(Node<T> *bt,Node<T> *pre){//中序線索化if(root!=NULL){inThread(bt->lchild,pre);//遞歸左子樹線索化if(bt->lchild!=NULL){//沒有左孩子bt->ltag=thread;//前驅線索bt->lchild=pre;//左孩子指針執行前驅}if(pre->rchild!=NULL){//沒有右孩子pre->rtag=thread;//后繼線索pre->rchild=bt;//右孩子指向后繼}pre=bt;//保持pre指向bt的前驅inThread(bt->rchild,pre);//遞歸右子樹線索化} }【查找后繼結點】
首先判斷當前結點是否已有線索,若已有,則可直接得到后繼,若沒有,則要尋找當前結點的右孩子的最左下結點
template<class T> Node<T> * ThreadTree<T>::findNext(Node<T> *bt){//查找結點bt的后繼Node<T> *q;//后繼if(bt->rtag==thread)//已有線索,直接得到后繼結點q=bt->rchild;else{q=bt->rchild;//工作指針q指向bt的右孩子while(q->ltag==link)//查找最左下結點q=q->lchild;}return q; }【遍歷操作】
對線索鏈表進行中序遍歷操作時,只要尋找到中序序列的第一個結點,然后依次訪問其后繼即可
template<class T> void ThreadTree<T>::inOrder(){//中序遍歷if(root==NULL)return;else{Node<T> *p;p=root;while(p->ltag==link)//尋找中序遍歷序列的第一個結點p=p->lchild;cout<<p->data;while(p->rchild!=NULL){//當結點p存在后繼,依次訪問其后繼p=findNext(p);cout<<p->data;}} }?
總結
以上是生活随笔為你收集整理的理论基础 —— 二叉树 —— 线索链表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 相离的圆(51Nod-1278)
- 下一篇: 流水线调度(51Nod-1205)