1、定義html
二叉排序樹,又叫二叉查找樹,它或者是一棵空樹;或者是具備如下性質的二叉樹:
1. 若它的左子樹不空,則左子樹上全部節點的值均小於它的根節點的值;
2. 若它的右子樹不空,則右子樹上全部節點的值均大於它的根節點的值;
3. 它的左右子樹也分別爲二叉排序樹。node
以下圖所示:ios
2、二叉排序樹的C++實現數據結構
一、結點定義ide
爲簡單起見,這裏將結點的鍵值類型設爲int.函數
class BSTNode { public: int key; //結點的值 BSTNode* left; //結點的左孩子 BSTNode* right; //結點的右孩子 BSTNode* parent; //結點的雙親 /*構造函數*/ BSTNode():parent(NULL) {} BSTNode(int key, BSTNode* left, BSTNode* right, BSTNode* parent) :key(key), left(left), right(right), parent(parent) {} };
二、二叉排序樹的各類操做post
class BSTree { private: BSTNode* root; //根節點 public: /*構造函數*/ BSTree() :root(NULL) {}; /*獲取根節點*/ BSTNode* getRoot() {return root;} /*將鍵值key插入到二叉樹中*/ void insert(int key); /*將結點插入到二叉樹中*/ void insert(BSTNode*& root, BSTNode* node); /*先序遍歷*/ void preOrder(BSTNode* root); /*中序遍歷*/ void inOrder(BSTNode* root); /*後序遍歷*/ void postOrder(BSTNode* root); /*查找二叉樹中鍵值爲key的結點並返回*/ BSTNode* search(BSTNode* node, int key); /*找出二叉樹中鍵值最小的結點並返回*/ BSTNode* minimum(BSTNode* node); /*找出二叉樹中鍵值最大的結點並返回*/ BSTNode* maximum(BSTNode* node); /*找到二叉樹結點node的後繼結點*/ BSTNode* successor(BSTNode* node); /*找到二叉樹結點node的前驅結點*/ BSTNode* predecessor(BSTNode* node); /*移除鍵值爲key的結點*/ BSTNode* remove(BSTNode*& root, int key); /*銷燬二叉排序樹*/ void destroy(BSTNode* root); };
三、插入測試
在二叉排序樹進行插入操做時,每次插入的結點都是二叉排序樹上新的葉子結點。能夠將結點插入到一棵已經存在的二叉排序樹上,也能夠經過插入結點來構造一棵二叉排序樹。this
/* * 將結點插入到二叉樹中 * * 參數說明: * root 二叉樹的根結點 * node 要插入的結點 */ void BSTree::insert(BSTNode*& root, BSTNode* node) { BSTNode* y = NULL; BSTNode* x = root; /*找到要插入的位置*/ while (x != NULL) { y = x; if (node->key > x->key) x = x->right; else x = x->left; } /*插入結點*/ node->parent = y; if (y == NULL) root = node; else if(y->key > node->key) y->left = node; else y->right = node; } void BSTree::insert(int key)
{ BSTNode* node = new BSTNode(key, NULL, NULL, NULL); insert(root, node); }
四、遍歷spa
二叉排序樹的遍歷同普通二叉樹同樣分爲先序、中序、後序遍歷,實現起來也沒有差異。須要注意的是,中序遍歷二叉排序樹會獲得一個關鍵字的有序序列。
4.1 先序遍歷
/*先序遍歷*/ void BSTree::preOrder(BSTNode* root) { if (root != NULL) { cout << root->key; preOrder(root->left); preOrder(root->right); } }
4.2 中序遍歷
中序遍歷二叉排序樹會獲得一個關鍵字的有序序列。
/*中序遍歷*/ void BSTree::inOrder(BSTNode* root) { if (root != NULL) { inOrder(root->left); cout << root->key; inOrder(root->right); } }
4.3 後序遍歷
/*後序遍歷*/ void BSTree::postOrder(BSTNode* root) { if (root != NULL) { postOrder(root->left); postOrder(root->right); cout << root->key; } }
五、查找
當二叉樹非空時,首先將待查找的鍵值與根節點的鍵值比較,若大於根節點的鍵值,則繼續查找右子樹,不然查找左子樹。重複上述過程,直至查找成功返回找到的結點,不然返回空。
BSTNode* BSTree::search(BSTNode* node, int key) { if (node == NULL || node->key == key) return node; if (node->key < key) search(node->right, key); else search(node->left, key); }
六、最大值與最小值
在一棵非空二叉排序樹中,最小值結點爲最左下結點,最大值結點爲最右下結點。
6.1 獲取最小值結點
BSTNode* BSTree::minimum(BSTNode* node) { if (node->left == NULL) return node; minimum(node->left); }
6.2 獲取最大值結點
BSTNode* BSTree::maximum(BSTNode* node) { if (node->right == NULL) return node; maximum(node->right); }
七、前驅結點與後繼結點
結點node的前驅結點是全部鍵值小於node的結點中的最大結點,也就是node的左子樹的最大結點;
結點node的後繼結點是全部鍵值大於node的結點中的最小結點,也就是node的右子樹的最小結點。
7.1 前驅結點
(1)若結點node的左子樹非空,則左子樹的最大結點即爲node的前驅結點;
(2)若結點node的左子樹爲空
(2.1)若node爲右孩子,則node的前驅結點爲node的父結點;
(2.2)若node爲左孩子,則查找結點node的最低的父結點,且該父結點要有右孩子,此最低父結點即爲node的前驅結點。
/*查找結點node的前驅節點*/ BSTNode* BSTree::predecessor(BSTNode* node) { /*(1)左子樹非空,返回左子樹最大值結點*/ if (node->left != NULL) return maximum(node->left); /*(2)*/ BSTNode* pnode = node->parent; while (pnode != NULL&&node == pnode->left) { node = pnode; pnode = pnode->parent; } return pnode; }
7.2 後繼結點
(1)若結點node的右子樹非空,則右子樹的最小結點即爲node的後繼結點;
(2)若結點node的右子樹爲空
(2.1)若結點node爲左孩子,則node的後繼結點即爲其父結點;
(2.2)若結點node爲右孩子,則查找node的最低的父結點,且該父結點要有左孩子,此最低父結點即爲node的後繼結點。
/*查找node的後繼結點*/ BSTNode* BSTree::successor(BSTNode* node) { /*(1)右子樹非空,返回右子樹最小值結點*/ if (node->right != NULL) return minimum(node->right); /*(2)*/ BSTNode* pnode = node->parent; while (pnode != NULL&&node == pnode->right) { node = pnode; pnode = pnode->parent; } return pnode; }
八、刪除結點
假設要刪除的結點爲*p(p爲指向要刪除結點的指針),其雙親結點爲*f,不失通常性,可設*p是*f的左孩子。
(1)若*p結點爲葉子結點,即PL和PR均爲空,則只需修改f->left爲空便可;
(2)若*p結點只有左子樹PL或者只有右子樹PR,這隻需令PL和PR直接成爲f的左孩子便可;
(3)若*p結點的左子樹和右子樹均不爲空,在刪去*p以後,爲保持其餘元素之間的相對位置不變,能夠有兩種作法:
(3.1)作法一:令*s爲*p的左子樹PL的最右結點,則令*p的左子樹PL爲*f的左子樹,*p的右子樹PR爲*s的右子樹;
(3.2)作法二:令*p的直接前驅(或直接後繼)替代*p,而後再從二叉排序樹中刪除它的直接前驅(或直接後繼)。
下面的代碼當遇到狀況(3)時,採用作法一:
/*獲取要刪除的結點並返回*/ BSTNode* BSTree::remove(BSTNode*& root, int key) { BSTNode* node = search(root, key); printf("%d\n", node->key); if (node != NULL) { if (node->left == NULL && node->right == NULL) //node爲葉子結點 { if (node->parent == NULL) //要刪除的結點爲根結點 return node; else if (node->parent->left == node)//判斷要刪除點在雙親結點的左邊仍是右邊 node->parent->left = NULL; else node->parent->right = NULL; } else if (node->left == NULL) //node左子樹爲空 { if (node->parent == NULL) //要刪除的結點爲根結點 { this->root = node->right; node->right->parent = NULL; } else if (node->parent->left == node)//判斷要刪除點在雙親結點的左邊仍是右邊 node->parent->left = node->right; else node->parent->right = node->right; } else if (node->right == NULL) //node右子樹爲空 { if (node->parent == NULL) //要刪除的結點爲根結點 { this->root = node->left; node->left->parent = NULL; } else if (node->parent->left == node)//判斷要刪除點在雙親結點的左邊仍是右邊 node->parent->left = node->left; else node->parent->right = node->left; } else //node左右子樹均不爲空 { BSTNode* lnode = node->left; //lnode初始爲node左子樹的根節點 while (lnode->right) //找到node左子樹的最右結點賦值爲lnode lnode = lnode->right; lnode->right = node->right; //將node的右子樹變成lnode的右子樹 node->right->parent = lnode; if (node->parent == NULL) //要刪除的結點爲根結點 { this->root = node->right; if (node->right->left != NULL) { BSTNode* leftDownNode = minimum(node->right); leftDownNode->left = node->left; node->left->parent = leftDownNode; } else { node->right->left = node->left; node->left->parent = node->right; } } else if (node->parent->left == node) //將node的左子樹替換node的位置 { node->parent->left = node->left; node->left->parent = node->parent; } else if (node->parent->right == node) { node->parent->right = node->left; node->left->parent = node->parent; } } } return node; }
九、銷燬
銷燬二叉排序樹與銷燬普通二叉樹沒有區別,這裏採用後序遍歷的方式來銷燬。
/*銷燬二叉樹*/ void BSTree::destroy(BSTNode* root) { if (root == NULL) return; destroy(root->left); destroy(root->right); delete root; }
3、所有程序
一、頭文件bstree.h
#include <iostream> #include <cstdio> #include <cstring> using namespace std; class BSTNode { public: int key; //結點的值 BSTNode* left; //結點的左孩子 BSTNode* right; //結點的右孩子 BSTNode* parent; //結點的雙親 /*構造函數*/ BSTNode():parent(NULL) {} BSTNode(int key, BSTNode* left, BSTNode* right, BSTNode* parent) :key(key), left(left), right(right), parent(parent) {} }; class BSTree { private: BSTNode* root; //根節點 public: /*構造函數*/ BSTree() :root(NULL) {}; /*獲取根節點*/ BSTNode* getRoot(); /*將鍵值key插入到二叉樹中*/ void insert(int key); /*將結點插入到二叉樹中*/ void insert(BSTNode*& root, BSTNode* node); /*先序遍歷*/ void preOrder(BSTNode* root); /*中序遍歷*/ void inOrder(BSTNode* root); /*後序遍歷*/ void postOrder(BSTNode* root); /*查找二叉樹中鍵值爲key的結點並返回*/ BSTNode* search(BSTNode* node, int key); /*找出二叉樹中鍵值最小的結點並返回*/ BSTNode* minimum(BSTNode* node); /*找出二叉樹中鍵值最大的結點並返回*/ BSTNode* maximum(BSTNode* node); /*找到二叉樹結點node的後繼結點*/ BSTNode* successor(BSTNode* node); /*找到二叉樹結點node的前驅結點*/ BSTNode* predecessor(BSTNode* node); /*移除鍵值爲key的結點*/ BSTNode* remove(BSTNode*& root, int key); /*銷燬二叉排序樹*/ void destroy(BSTNode* root); }; BSTNode* BSTree::getRoot() { return root; } /*先序遍歷*/ void BSTree::preOrder(BSTNode* root) { if (root != NULL) { cout << root->key; preOrder(root->left); preOrder(root->right); } } /*中序遍歷*/ void BSTree::inOrder(BSTNode* root) { if (root != NULL) { inOrder(root->left); cout << root->key; inOrder(root->right); } } /*後序遍歷*/ void BSTree::postOrder(BSTNode* root) { if (root != NULL) { postOrder(root->left); postOrder(root->right); cout << root->key; } } BSTNode* BSTree::search(BSTNode* node, int key) { if (node == NULL || node->key == key) return node; if (node->key < key) search(node->right, key); else search(node->left, key); } BSTNode* BSTree::minimum(BSTNode* node) { if (node->left == NULL) return node; minimum(node->left); } BSTNode* BSTree::maximum(BSTNode* node) { if (node->right == NULL) return node; maximum(node->right); } /*查找node的後繼結點*/ BSTNode* BSTree::successor(BSTNode* node) { /*(1)右子樹非空,返回右子樹最小值結點*/ if (node->right != NULL) return minimum(node->right); /*(2)*/ BSTNode* pnode = node->parent; while (pnode != NULL&&node == pnode->right) { node = pnode; pnode = pnode->parent; } return pnode; } /*查找結點node的前驅節點*/ BSTNode* BSTree::predecessor(BSTNode* node) { /*(1)左子樹非空,返回左子樹最大值結點*/ if (node->left != NULL) return maximum(node->left); /*(2)*/ BSTNode* pnode = node->parent; while (pnode != NULL&&node == pnode->left) { node = pnode; pnode = pnode->parent; } return pnode; } /* * 將結點插入到二叉樹中 * * 參數說明: * root 二叉樹的根結點 * node 要插入的結點 */ void BSTree::insert(BSTNode*& root, BSTNode* node) { BSTNode* y = NULL; BSTNode* x = root; /*找到要插入的位置*/ while (x != NULL) { y = x; if (node->key > x->key) x = x->right; else x = x->left; } /*插入結點*/ node->parent = y; if (y == NULL) root = node; else if(y->key > node->key) y->left = node; else y->right = node; } void BSTree::insert(int key) { BSTNode* node = new BSTNode(key, NULL, NULL, NULL); insert(root, node); } //BSTNode* BSTree::remove(BSTNode*& root, int key) //{ // BSTNode* x = NULL; // BSTNode* y = NULL; // // BSTNode* z = search(root, key); // if (z->left == NULL || z->right == NULL) // y = z; // else y = successor(z); // // if (y->left != NULL) // x = y->left; // else x = y->right; // // if (x != NULL) // x->parent = y->parent; // // if (y->parent == NULL) // root = x; // else if (y->parent->left == y) // y->parent->left = x; // else if (y->parent->right == y) // y->parent->right = x; // // if (y != z) // z->key = y->key; // // return y; //} /*獲取要刪除的結點並返回*/ BSTNode* BSTree::remove(BSTNode*& root, int key) { BSTNode* node = search(root, key); printf("%d\n", node->key); if (node != NULL) { if (node->left == NULL && node->right == NULL) //node爲葉子結點 { if (node->parent == NULL) //要刪除的結點爲根結點 return node; else if (node->parent->left == node)//判斷要刪除點在雙親結點的左邊仍是右邊 node->parent->left = NULL; else node->parent->right = NULL; } else if (node->left == NULL) //node左子樹爲空 { if (node->parent == NULL) //要刪除的結點爲根結點 { this->root = node->right; node->right->parent = NULL; } else if (node->parent->left == node)//判斷要刪除點在雙親結點的左邊仍是右邊 node->parent->left = node->right; else node->parent->right = node->right; } else if (node->right == NULL) //node右子樹爲空 { if (node->parent == NULL) //要刪除的結點爲根結點 { this->root = node->left; node->left->parent = NULL; } else if (node->parent->left == node)//判斷要刪除點在雙親結點的左邊仍是右邊 node->parent->left = node->left; else node->parent->right = node->left; } else //node左右子樹均不爲空 { BSTNode* lnode = node->left; //lnode初始爲node左子樹的根節點 while (lnode->right) //找到node左子樹的最右結點賦值爲lnode lnode = lnode->right; lnode->right = node->right; //將node的右子樹變成lnode的右子樹 node->right->parent = lnode; if (node->parent == NULL) //要刪除的結點爲根結點 { this->root = node->right; if (node->right->left != NULL) { BSTNode* leftDownNode = minimum(node->right); leftDownNode->left = node->left; node->left->parent = leftDownNode; } else { node->right->left = node->left; node->left->parent = node->right; } } else if (node->parent->left == node) //將node的左子樹替換node的位置 { node->parent->left = node->left; node->left->parent = node->parent; } else if (node->parent->right == node) { node->parent->right = node->left; node->left->parent = node->parent; } } } return node; } /*銷燬二叉樹*/ void BSTree::destroy(BSTNode* root) { if (root == NULL) return; destroy(root->left); destroy(root->right); delete root; }
二、測試文件bstree.cpp
1 #include "bstree.h" 2 3 int main() 4 { 5 int a[] = { 1, 5, 4, 3, 2, 6 }; 6 7 BSTree* tree = new BSTree(); 8 for (int i = 0; i < 6;i++) 9 tree->insert(a[i]); 10 11 cout << "先序遍歷:"; 12 tree->preOrder(tree->getRoot()); 13 cout << endl; 14 15 cout << "中序遍歷:"; 16 tree->inOrder(tree->getRoot()); 17 cout << endl; 18 19 cout << "後序遍歷:"; 20 tree->postOrder(tree->getRoot()); 21 cout << endl; 22 23 cout << "最小值:"; 24 BSTNode* minNode = tree->minimum(tree->getRoot()); 25 if(minNode != NULL) 26 cout << minNode->key << endl; 27 28 cout << "最大值:"; 29 BSTNode* maxNode = tree->maximum(tree->getRoot()); 30 if (maxNode != NULL) 31 cout << maxNode->key << endl; 32 33 34 BSTNode* node = tree->search(tree->getRoot(), 6); 35 BSTNode* snode = tree->successor(node); 36 if (snode != NULL) 37 cout << snode->key << endl; 38 39 BSTNode* pnode = tree->predecessor(node); 40 if (pnode != NULL) 41 cout << pnode->key << endl; 42 43 BSTNode* root = tree->getRoot(); 44 BSTNode* dnode = tree->remove(root, 5); 45 cout << "刪除" << dnode->key << "後先序遍歷:" << endl; 46 if (dnode) delete dnode; 47 tree->preOrder(tree->getRoot()); 48 cout << endl; 49 50 cout << "銷燬二叉樹" << endl; 51 tree->destroy(root); 52 }
三、結果
先序遍歷:154326 中序遍歷:123456 後序遍歷:234651 最小值:1 最大值:6 5 刪除5後先序遍歷: 14326 銷燬二叉樹
4、參考
一、http://www.cnblogs.com/skywang12345/p/3576373.html
二、 嚴蔚敏、吳偉民《數據結構》