!!版權聲明:本文為博主原創文章,版權歸原文作者和博客園共有,謝絕任何形式的 轉載!!
作者:mohist
--- 歡迎指正---
二叉樹特點:
要么為空樹;要么,當前結點的左孩子比當前結點值小,當前結點的右孩子比當前結點的值大。
1、插入:
1.1 插入結點的值比當前結點的值小,繼續找當前結點的左子樹,
1.2 插入結點的值比當前結點的值大,繼續找當前結點的右子樹,
1.3 找到合適的位置了,插入樹。
2、刪除:
2.1 刪除結點是葉子結點,直接將其刪除即可
2.2 刪除結點只有左孩子或者只有右孩子,將其孩子結點刪除,並將指向孩子結點的分支設置為空,c++是設置為NULL。不過更好的做法是,將孩子結點的值替換到當前結點,再刪除孩子結點即可。
2.3 刪除的結點同時含有左孩子與右孩子,需要找到刪除結點的后繼結點,將后繼結點作為當前結點。
完整源碼:
#include <iostream> using namespace std; struct node { // 數據域 int data; // 左節點 node *lc; // 右結點 node *rc; // 構造函數 node() : data(0) , lc(NULL) , rc(NULL) { } }; // bst class bstree { public: enum { hmax_size_32767 = 32767, hmin_size_0 = 0, }; public: // 構造函數 bstree() : root(NULL) , size(0) { } // 析構函數 virtual ~bstree(){} int get_size() { return size; } // 插入結點 void insert_node(int data) { int cur_size = get_size(); if (hmax_size_32767 == cur_size) { cout << "insert node error, the size of the tree is max" << endl; return ; } root = insert(root, data); } // 先序遍歷(前序遍歷) void pre_order() { pre_order_traverse(root); } // 中序遍歷 void in_order() { in_order_traverse(root); } // 后序遍歷 void post_order() { post_order_traverse(root); } /* 查找某個結點 int key - 查找結果 返回值: NULL : 可能為root為空 或者 沒有找到 != NULL, 找到結點 */ node* query(int key) { if (NULL == root) { cout << "query error, root = null" << endl; return NULL; } return query_node(root, key); } // 刪除樹 void remove_all() { if (NULL == root) { cout << "remove all failed, root = null" << endl; return; } remove_all(root); int cur_size = get_size(); if (0 == cur_size) root = NULL; } // 刪除某個結點 void remove_node(int del_data) { if (NULL == root) { cout << "remove node error, root = null" << endl; return; } node *parent_node = NULL; node *del_node = root; // 找到刪除結點的父節點與刪除結點 while (del_node) { if (del_data == del_node->data) break; else if (del_data > del_node->data) { parent_node = del_node; del_node = del_node->rc; } else if (del_data < del_node->data) { parent_node = del_node; del_node = del_node->lc; } } // 若沒有找到要刪除的結點 if (NULL == del_node) { cout << "remove node error, " << del_data << " was not find" << endl; return; } // 1、若刪除的結點沒有左子樹和右子樹 if ( (NULL == del_node->lc) && (NULL == del_node->rc) ) { // 為什么要先判斷根結點,因為根結點的父節點找不到,結果為NULL, // 1.1 可能只有一個根結點, 將root釋放值為空 if (del_node == root) { root = NULL; delete del_node; del_node = NULL; dec_size(); return; } // 1.2 非根結點,那就是葉子結點了, 將父節點指向刪除結點的分支指向NULL if (del_node == parent_node->lc) parent_node->lc = NULL; else if (del_node == parent_node->rc) parent_node->rc = NULL; // 釋放結點 delete del_node; del_node = NULL; dec_size(); } // 2、若刪除結點只有左孩子,沒有右孩子 else if ( (NULL != del_node->lc) && (NULL == del_node->rc) ) { // 2.1 刪除結點為根結點,則將刪除結點的左孩子替代當前刪除結點 if (del_node == root) { root = root->lc; } // 2.2 其他結點,將刪除結點的左孩子作為父節點的左孩子 else { if (parent_node->lc == del_node) parent_node->lc = del_node->lc; else if (parent_node->rc == del_node) parent_node->rc = del_node->lc; } delete del_node; del_node = NULL; dec_size(); } // 3、若刪除結點只有右孩子 else if ( (NULL == del_node->lc) && (NULL != del_node->rc) ) { // 3.1 若為根結點 if (root == del_node) { root = root->rc; } else { if (del_node == parent_node->lc) parent_node->lc = del_node->rc; else if (del_node == parent_node->rc) parent_node->rc = del_node->rc; } delete del_node; del_node = NULL; dec_size(); } // 4、若刪除結點既有左孩子,又有右孩子,需要找到刪除結點的后繼結點作為根結點 else if ( (NULL != del_node->lc) && (NULL != del_node->rc) ) { node *successor_node = del_node->rc; parent_node = del_node; while (successor_node->lc) { parent_node = successor_node; successor_node = successor_node->lc; } // 交換后繼結點與當前刪除結點的數據域 del_node->data = successor_node->data; // 將指向后繼結點的父節點的孩子設置后繼結點的右子樹 if (successor_node == parent_node->lc) parent_node->lc = successor_node->rc; else if (successor_node == parent_node->rc) parent_node->rc = successor_node->rc; // 刪除后繼結點 del_node = successor_node; delete del_node; del_node = NULL; dec_size(); } } // 返回以proot為根結點的最小結點 node *get_min_node(node *proot) { if (NULL == proot->lc) return proot; return get_min_node(proot->lc); } // 返回以proo為根節點的最大結點 node *get_max_node(node *proot) { if (NULL == proot->rc) return proot; return get_max_node(proot->rc); } // 返回根節點 node *get_root_node() { return root; } // 返回proot結點的父節點 node *get_parent_node(int key) { // 當前結點 node *cur_node = NULL; // 父節點 node *parent_node = NULL; cur_node = root; // 標記是否找到 bool is_find = false; while (cur_node) { if (key == cur_node->data) { is_find = true; break; } // 因為比當前結點的值還要小,所以需要查找當前結點的左子樹 else if (key < cur_node->data) { parent_node = cur_node; cur_node = cur_node->lc; } // 同上, 查找當前結點的右子樹 else if (key > cur_node->data) { parent_node = cur_node; cur_node = cur_node->rc; } } return (true == is_find)? parent_node : NULL; } private: //查找某個值 node *query_node(node *proot, int key) { if (NULL == proot) { return proot; } if (proot->data == key) return proot; else if (proot->data > key) { return query_node(proot->lc, key); } else if (proot->data < key) { return query_node(proot->rc, key); } return NULL; } // 后序遍歷刪除所有結點 void remove_all(node *proot) { if (NULL != proot) { remove_all(proot->lc); remove_all(proot->rc); delete proot; dec_size(); } } // 先序遍歷 void pre_order_traverse(node *proot) { if (NULL != proot) { cout << proot->data << ", "; pre_order_traverse(proot->lc); pre_order_traverse(proot->rc); } } // 中序遍歷 void in_order_traverse(node *proot) { if (NULL != proot) { in_order_traverse(proot->lc); cout << proot->data << ", "; in_order_traverse(proot->rc); } } // 后續遍歷 void post_order_traverse(node *proot) { if (NULL != proot) { post_order_traverse(proot->lc); post_order_traverse(proot->rc); cout << proot->data << ", "; } } // 插入結點 node *insert(node *proot, int data) { // 結點不存在, 則創建 if (NULL == proot) { node *new_node = new(std::nothrow) node; if (NULL != new_node) { new_node->data = data; proot = new_node; // 結點+1; add_size(); } return proot; } // 插入值比當前結點值還要小, 則應該插入到當前節點的左邊 if (proot->data > data) { proot->lc = insert(proot->lc, data); } // 插入之比當前結點值還要打,則應該插入到當前結點的右邊 else if (proot->data < data) { proot->rc = insert(proot->rc, data); } // 相等,則不插入結點。 return proot; } // size + 1 void add_size() { if (hmax_size_32767 == size) return ; size++; } // size - 1 void dec_size() { if ( hmin_size_0 == size) { return ; } size--; } private: // 根結點 node *root; // 當前樹的結點個數 int size; }; // 測試代碼 int main() { bstree tree; // tree.insert_node(50); tree.insert_node(30); tree.insert_node(10); tree.insert_node(0); tree.insert_node(20); tree.insert_node(40); tree.insert_node(70); tree.insert_node(90); tree.insert_node(100); tree.insert_node(60); tree.insert_node(80); // 前序遍歷 cout << "前序遍歷" << endl; tree.pre_order(); cout << endl; // 中序遍歷 cout << "中序遍歷" << endl; tree.in_order(); cout << endl; // 后序遍歷 cout << "后序遍歷" << endl; tree.post_order(); cout << endl; cout << "刪除結點開始,結束請輸入10086" << endl; int del_key = 0; while (true) { cout << "輸入刪除結點值 = "; cin >> del_key; if (10086 == del_key) break; tree.remove_node(del_key); cout << "刪除后,結點個數 = " << tree.get_size() << endl; cout << "刪除后, 中序遍歷結果:" ;// << endl; tree.in_order(); cout << endl << endl; } tree.remove_all(); return 0; }
測試結果: