二叉樹一個重要的資料結構,如何方便直觀的顯示一棵樹對於學習非常重要。
現設計了如下演算法:
編寫函數displaytree(二叉樹的根指標,資料值寬度,螢幕的寬度)輸出樹的直觀。輸出的二叉樹是垂直列印的,同層的節點在同一行上。
問題描述:
假設資料寬度datawidth=2,而螢幕寬度screenwidth為64=2^6,假設節點的輸出位置用(層號,須列印的空格數)來界定。
第0層:根在(0,32)處輸出;
第1層:因為根節點縮排了32個空格,所以下一層的位移量(offset)為32/2 = 16 = screenwidth/2^2。即第一層的兩個節點的位置(1,32-offset),(1,32+offset) 即(1,16),(1,48)。
第2層:第二層的位移量offset為screenwidth/23。第二層的四個節點的位置分別是(2,16-offset),(2,16+offset),(2,48-offset),(2,48+offset)即(2,8),(2,24),(2,40),(2,56)。……
第i層: 第i層的位移量offset為screenwidth/2i+1。第i層的每個節點的位置是訪問第i-1層其雙親節點時確定的。假設其雙親的位置為(i- 1,parentpos)。若其第i層的節點是其左孩子,那末左孩子的位置是(i,parentpos-offset),右孩子的位置是(i,parentpos+offset)。
利用二叉樹的層次遍曆演算法實現。利用兩個隊列Q,QI。
隊列Q中存放節點資訊。
隊列QI中存相應於隊列Q中的節點的位置資訊,包括層號、位置,是否換行、需要列印的空格數。
當節點被加入到Q時,根據前一個節點的資訊來計算當期的列印資訊,並且將相應的列印資訊被存到QI中。
class Node<br />{<br />public:<br />int key;<br />Node *left;<br />Node *right;<br />Node *parent;<br />Node(){};<br />Node(int key){this->key=key;left=right=parent=NULL;}<br />};<br />class DisplayInfo<br />{<br />public:<br />int level;<br />int pos; //結點在螢幕中的絕對位置<br />bool enter;<br />int spaceNum;<br />};<br />class BST<br />{<br />public:<br />Node *root;<br />BST(){root=NULL;}<br />void insert(int key);<br />void BFSDisplayTree(void);<br />void NatureDisplayTree(void);<br />};
程式如下:
void BST::NatureDisplayTree()<br />{<br />int i;<br /> list<Node *>Q;<br /> list<DisplayInfo>QI;<br /> int screenWidth=64;<br /> int dataWidth=2;<br /> DisplayInfo info; //將插入隊列的結點的列印資訊<br /> DisplayInfo preInfo; //隊尾的結點的列印資訊<br /> Node *curNode; //隊列當前取出的結點<br /> DisplayInfo curInfo; //隊列當前取出的結點的列印資訊<br /> if(!root)<br /> {<br /> printf("Tree is empty !/n");<br /> return;<br /> }<br /> printf("Nature Display Tree:/n");<br /> Q.push_back(root);<br /> info.level=1;<br /> info.enter=true;<br /> info.spaceNum=screenWidth>>info.level;<br /> info.pos=info.spaceNum;<br /> QI.push_back(info);<br /> preInfo=info;<br /> while(Q.size())<br /> {<br /> curNode=Q.front();<br /> Q.pop_front();<br /> curInfo=QI.front();<br /> if(curInfo.enter)<br /> printf("/n/n");<br /> for (i=0;i<curInfo.spaceNum;i++)<br />printf(" ");<br /> printf("%2d",curNode->key);<br /> QI.pop_front();<br /> if(curNode->left)<br /> {<br /> Q.push_back(curNode->left);<br /> info.level=curInfo.level+1;<br /> info.pos=curInfo.pos-(screenWidth>>info.level);<br /> if(info.level>preInfo.level)<br /> {<br /> info.enter=true;<br /> info.spaceNum=info.pos;<br /> }<br /> else<br /> {<br /> info.enter=false;<br /> info.spaceNum=info.pos-preInfo.pos;<br /> }<br /> info.spaceNum-=dataWidth;<br /> QI.push_back(info);<br /> preInfo=info;</p><p> }<br /> if(curNode->right)<br /> {<br /> Q.push_back(curNode->right);<br /> info.level=curInfo.level+1;<br /> info.pos=curInfo.pos+(screenWidth>>info.level);<br /> if(info.level>preInfo.level)<br /> {<br /> info.enter=true;<br /> info.spaceNum=info.pos;<br /> }<br /> else<br /> {<br /> info.enter=false;<br /> info.spaceNum=info.pos-preInfo.pos;<br /> }<br /> info.spaceNum-=dataWidth;<br /> QI.push_back(info);<br /> preInfo=info;<br /> }</p><p> }<br /> printf("/n");<br />}
需要注意的是:如果將插入的結點和隊尾的結點的level不同,說明需要換行
採用隊列的方式是為了實現廣度優先遍曆:從根結點開始,一層一層的將結點加入到隊列中。
遍曆的過程也是顯示的過程
結果如下