資料結構與演算法之十 提高二叉搜尋樹的效率
阿新 • • 發佈:2018-12-25
/*寫一個程式以實現插入、刪除且遍歷線索二叉搜尋樹,這裡樹中的每個節點包含一個字典程式。*/ using System; using System.Text; namespace Threads { class Node { /*兩個線索域;lthread,rthread;1:表示子節點;0:表示線索.*/ public int lthread; /*左線索標誌*/ public Node lchild; /*左子節點/ public string info; /*資料域*/ public Node rchild; /*右子節點*/ public int rthread; /*右線索標誌*/ public Node(int lt, Node lc, string i, Node rc, int rt) { lthread = lt; lchild = lc; info = i; rchild = rc; rthread = rt; } } class Operations { Node head; public Operations() { /*在一個線索二叉樹種,我們增加一個節點,即頭節點.線索樹作為頭節點的左子樹,即頭點指向樹的根節點.當樹為空的時候,頭節點左子節點指向本身*/ head = new Node(0, head, "頭節點", head, 0); head.lchild = head; head.rchild = head; }//建構函式初始化的時候,頭節點的左,右子節點指向本身. public void find(string element, ref Node parent, ref Node currentNode) { /*搜尋方法,查詢你要找的節點位置與之父節點的位置.*/ if (head.lchild == head) { /*如果沒有找到節點為null,且父節點為頭節點*/ currentNode = null; parent = head; return; } currentNode = head.lchild; parent = head; while (currentNode.info != element) { parent = currentNode; if (String.Compare(element,currentNode.info)<0) //如果元素小於當前節點 { if (currentNode.lthread == 1) //判斷當前節點的左線索標誌,如果為1,則指向當前節點的左子節點. currentNode = currentNode.lchild; else //否則,如果左線索標誌為0,則設定當前節點為空. { currentNode = null; return; } } else { if (currentNode.rthread == 1) //如果當前節點的右線索標誌為1,則指向當前節點的右子節點. currentNode = currentNode.rchild; else //否則,右線索標誌為0,則設定當前節點為空 { currentNode = null; return; } } } } public void insert(string element) /*在二叉樹中插入一個節點.*/ { Node tmp, parent = null, currentNode = null; // find(element, ref parent, ref currentNode); //呼叫查詢當前元素節點,當前元素父節點. if (currentNode != null) { /*在二叉搜尋樹中不允許,重複節點.*/ Console.WriteLine("\n不允許重複單詞."); return; } tmp = new Node(0, null, element, null, 0); //為tmp新節點分配記憶體. if (parent == head) /*如果父節點為頭節點,則插入節點為根節點.*/ { head.lthread = 1; /*設定頭節點的左線索標誌為1*/ head.lchild = tmp; /*設定頭節點的左子節點為要新節點.*/ tmp.lchild = head; /*新節點的左線索為頭節點.*/ tmp.rchild = head; /*新節點的右線索為頭節點.*/ } else { if (String.Compare(element,parent.info)<0) { /*要插入的新節點比父節點小*/ tmp.lchild = parent.lchild; tmp.rchild = parent; parent.lthread = 1; parent.lchild = tmp; } else { /*要插入的新節點比父節點要大!*/ tmp.rchild = parent.rchild; tmp.lchild = parent; parent.rthread = 1; parent.rchild = tmp; } } } public Node Inorder_successor(Node currentNode) //中序編歷查詢後繼節點 { /*中序:左子樹< 根<右子樹 */ Node successor; if (currentNode.rthread == 0) successor = currentNode.rchild; else { currentNode = currentNode.rchild; while (currentNode.lthread == 1) { currentNode = currentNode.lchild; } successor = currentNode; } return successor; } public Node Inorder_predecessor(Node currentNode) /*利用中序編歷查詢前驅節點.*/ { Node predecessor; if (currentNode.lthread == 0) predecessor = currentNode.lchild; else { currentNode = currentNode.lchild; while (currentNode.rthread == 1) { currentNode = currentNode.rchild; } predecessor = currentNode; } return predecessor; } public void Inorder_traversal() /*執行樹的中序編歷*/ { Node currentNode = null; if (head.lchild == head) { Console.WriteLine("樹空!"); return; } currentNode = head.lchild; while (currentNode.lthread == 1) { currentNode = currentNode.lchild; } Console.Write(currentNode.info + " "); while (true) { currentNode = Inorder_successor(currentNode); if (currentNode == head) break; Console.Write(currentNode.info + " "); } Console.WriteLine(); } public void remove() /*從樹種移除節點*/ { if (head.lchild == head) { Console.WriteLine("樹空"); return; } Node parent = null, currentNode = null; string element; Console.Write("請鍵入要刪除單詞:"); element = Console.ReadLine(); find(element, ref parent, ref currentNode); if (currentNode == null) { Console.WriteLine("\n在字典中沒有發現該單詞"); return; } /*依據不同的狀態,來刪除不同的子節點.*/ if (currentNode.lthread == 0 && currentNode.rthread == 0) case_1(ref parent, ref currentNode); if (currentNode.lthread == 1 && currentNode.rthread == 0) case_2(ref parent, ref currentNode); if (currentNode.lthread == 0 && currentNode.rthread == 1) case_2(ref parent, ref currentNode); if (currentNode.lthread == 1 && currentNode.rthread == 1) case_3(ref parent, ref currentNode); } public void case_1(ref Node parent, ref Node currentNode) { /* This function is invoked if the node to be removed is the leaf node */ if (parent == head) { head.lthread = 0; head.lchild = head; } else if (currentNode == parent.lchild) { parent.lthread = 0; parent.lchild = currentNode.lchild; } else { parent.rthread = 0; parent.rchild = currentNode.rchild; } } public void case_2(ref Node parent, ref Node currentNode) { /* This function is invoked if the node to be removed has only one child (left or right) */ Node child, successor, predecessor; if (currentNode.lthread == 1) child = currentNode.lchild; else child = currentNode.rchild; if (parent == head) head.lchild = child; else if (currentNode == parent.lchild) parent.lchild = child; else parent.rchild = child; successor = Inorder_successor(currentNode); predecessor = Inorder_predecessor(currentNode); if (currentNode.rthread == 1) successor.lchild = predecessor; else { if (currentNode.lthread == 1) predecessor.rchild = successor; } } public void case_3(ref Node parent, ref Node currentNode) { /* This function is invoked if the node to be removed has two children */ Node inorder_suc, inorder_parent; inorder_parent = currentNode; inorder_suc = currentNode.rchild; while (inorder_suc.lthread == 1) { inorder_parent = inorder_suc; inorder_suc = inorder_suc.lchild; } currentNode.info = inorder_suc.info; if (inorder_suc.lthread == 0 && inorder_suc.rthread == 0) case_1(ref inorder_parent, ref inorder_suc); else case_2(ref inorder_parent, ref inorder_suc); } static void Main(string[] args) { Operations t = new Operations(); while (true) { try { Console.WriteLine("\n選單"); Console.WriteLine("1. 插入操作"); Console.WriteLine("2.刪除操作"); Console.WriteLine("3.中序編歷操作"); Console.WriteLine("4. 退出"); Console.Write("\n請輸入您的選擇(1-4): "); char ch = Convert.ToChar(Console.ReadLine()); Console.WriteLine(); switch (ch) { case '1': { Console.Write("請輸入單詞: "); string word = Console.ReadLine(); t.insert(word); } break; case '2': { t.remove(); } break; case '3': { t.Inorder_traversal(); } break; case '4': return; default: { Console.WriteLine("無效選擇"); } break; } } catch (Exception e) { Console.WriteLine("請檢查您的值."); } } } } }