数据结构基础(17) --二叉查找树的设计与实现
二叉排序樹的特征
二叉排序樹或者是一棵空樹,或者是具有如下特性的二叉樹:
? ? 1.每一元素都有一個鍵值,?而且不允許重復;
? ? 2.若它的左子樹不空,則左子樹上所有結點的值均小于根結點的值;
? ? 3.若它的右子樹不空,則右子樹上所有結點的值均大于根結點的值;
? ? 4.它的左、右子樹也都分別是二叉排序樹。
二叉排序樹保存的元素構造
template <typename Type> class Element { public:Element(const Type& _key): key(_key) {}Element():key(0) {}Type key;//在這兒可以很容易的添加更多的數據//方便對Element進行擴展 };二叉排序樹節點的設計與實現
template <typename Type> class BstNode {friend class BsTree<Type>;public:BstNode(const Element<Type> &_data = 0,BstNode *_leftChild = NULL,BstNode *_rightChild = NULL): data(_data), leftChild(_leftChild), rightChild(_rightChild) {}const Type &getData() const{return data.key;}private://Node當中保存的是Element元素Element<Type> data;BstNode *leftChild;BstNode *rightChild;void display(int i); }; //中序遍歷二叉樹: //能夠保證該二叉樹元素按照遞增順序打印出來 template <typename Type> void BstNode<Type>::display(int i) {//首先訪問左子樹if (leftChild != NULL)leftChild->display(2*i);//訪問中間節點//Number表示為如果該樹為完全二叉樹/滿二叉樹, 其編號為幾std::cout << "Number: " << i << ", data.key = " << data.key << std::endl;//訪問右子樹if (rightChild != NULL)rightChild->display(2*i+1); }二叉排序樹的構造
template <typename Type> class BsTree { public: //構造與析構BsTree(BstNode<Type> *init = NULL): root(init) {}~BsTree(){if (!isEmpty())makeEmpty(root);}//二叉查找樹的三大主力:插入, 刪除, 搜索(又加入了一個迭代搜索)//插入bool insert(const Element<Type> &item);//刪除void remove(const Element<Type> &item){remove(item, root);}//遞歸搜索const BstNode<Type>* search(const Element<Type> &item){return search(item, root);}//迭代搜索const BstNode<Type> *searchByIter(const Element<Type> &item);//實用函數void display() const{if (root != NULL)root->display(1);}void visit(BstNode<Type> * currentNode) const{std::cout << "data.key = "<< currentNode->data.key << std::endl;}bool isEmpty() const{return root == NULL;}void makeEmpty(BstNode<Type> *subTree);//中序遍歷void levelOrder() const;private:const BstNode<Type>* search(const Element<Type> &item,const BstNode<Type> *currentNode);void remove(const Element<Type> &item,BstNode<Type> *¤tNode);private:BstNode<Type> *root; };二叉排序樹的插入算法
? ? 根據動態查找表的定義,“插入”操作在查找不成功時才進行;若二叉排序樹為空樹,則新插入的結點為新的根結點;否則,新插入的結點必為一個新的葉子結點,其插入位置由查找過程得到。
//二叉排序樹插入的實現與解析 template <typename Type> bool BsTree<Type>::insert(const Element<Type> &item) {//如果這是新插入的第一個節點if (root == NULL){root = new BstNode<Type>(item);root->leftChild = root->rightChild = NULL;return true;}BstNode<Type> *parentNode = NULL; //需要插入位置的父節點BstNode<Type> *currentNode = root; //需要插入的位置while (currentNode != NULL){//如果二叉樹中已經含有了該元素, 則返回插入出錯if (item.key == currentNode->data.key)return false;parentNode = currentNode;//如果要插入的元素大于當前指向的元素if (item.key < currentNode->data.key)currentNode = currentNode->leftChild; //向左搜索elsecurrentNode = currentNode->rightChild; //向右搜索}//此時已經查找到了一個比較合適的插入位置了if (item.key < parentNode->data.key)parentNode->leftChild = new BstNode<Type>(item);elseparentNode->rightChild = new BstNode<Type>(item);return true; }二叉排序樹的查找算法
若二叉排序樹為空,則查找不成功;否則:
? ? 1.若給定值等于根結點的關鍵字,則查找成功;
? ? 2.若給定值小于根結點的關鍵字,則繼續在左子樹上進行查找;
??? 3.若給定值大于根結點的關鍵字,則繼續在右子樹上進行查找。
//二叉排序樹搜索的設計與實現 //遞歸搜索 template <typename Type> const BstNode<Type>* BsTree<Type>::search(const Element<Type> &item,const BstNode<Type> *currentNode) {if (currentNode == NULL)return NULL;if (currentNode->data.key == item.key)return currentNode;if (item.key < currentNode->data.key)return search(item, currentNode->leftChild);elsereturn search(item, currentNode->rightChild); } //迭代搜索 template <typename Type> const BstNode<Type> *BsTree<Type>::searchByIter(const Element<Type> &item) {for (BstNode<Type> *searchNode = root;searchNode != NULL;/*empty*/){if (item.key == searchNode->data.key)return searchNode;if (item.key < searchNode->data.key)searchNode = searchNode->leftChild;elsesearchNode = searchNode->rightChild;}return NULL; }二叉排序樹的刪除算法
? ? 和插入相反,刪除在查找成功之后進行,并且要求在刪除二叉排序樹上某個結點之后,仍然保持二叉排序樹的特性。
?
刪除分三種情況:
? ? 1.被刪除的結點是葉子節點:其雙親結點中相應指針域的值改為“空”,?并將該節點刪除;
? ? 2.被刪除的結點只有左子樹或者只有右子樹:其雙親結點的相應指針域的值改為?“指向被刪除結點的左子樹或右子樹”,?然后刪除該節點;
? ? 3.被刪除的結點既有左子樹,也有右子樹:以其前驅替代之,然后再刪除該前驅結點;
//二叉排序樹節點刪除的實現與解析如下 template <typename Type> void BsTree<Type>::remove(const Element<Type> &item,BstNode<Type> *¤tNode) {if (currentNode != NULL){//如果要刪除的元素小于當前元素if (item.key < currentNode->data.key)remove(item, currentNode->leftChild); //向左搜索刪除//如果要刪除的元素大于當前元素else if (item.key > currentNode->data.key)remove(item, currentNode->rightChild); //向右搜索刪除//如果要刪除掉的元素等于當前元素(找到要刪除的元素了)// 并且當前節點的左右子女節點都不為空else if ((currentNode->leftChild != NULL) && (currentNode->rightChild != NULL)){//從當前節點的右子女節點開始,//不斷向左尋找, 找到從當前節點開始中序遍歷的第一個節點//找到的這一個節點是在當前子樹中, 大于要刪除的節點的第一個節點BstNode<Type> *tmp = currentNode->rightChild;while (tmp->leftChild != NULL)tmp = tmp->leftChild;//用搜索到的節點值覆蓋要刪除的節點值currentNode->data.key = tmp->data.key;//刪除搜索到的節點remove(currentNode->data, currentNode->rightChild);}//如果當前節點就是要刪除的節點//并且其左子女(和/或)右子女為空//默認包含了左右子女同時為空的情況://即: 在if中肯定為trueelse{BstNode<Type> *tmp = currentNode;//如果左子女為空if (currentNode->leftChild == NULL)//則用他的右子女節點頂替他的位置currentNode = currentNode->rightChild;//如果右子女為空else//則用他的左子女節點頂替他的位置currentNode = currentNode->leftChild;//釋放節點delete tmp;}} }二叉查找樹的幾個實用操作
//清空二叉樹 template <typename Type> void BsTree<Type>::makeEmpty(BstNode<Type> *subTree) {if (subTree != NULL){if (subTree->leftChild != NULL)makeEmpty(subTree->leftChild);if (subTree->rightChild != NULL)makeEmpty(subTree->rightChild);delete subTree;} } //二叉查找樹的層次遍歷 template <typename Type> void BsTree<Type>::levelOrder() const {std::queue< BstNode<Type> * > queue;queue.push(root);while (!queue.empty()){BstNode<Type> *currentNode = queue.front();queue.pop();visit(currentNode);if (currentNode->leftChild != NULL)queue.push(currentNode->leftChild);if (currentNode->rightChild != NULL)queue.push(currentNode->rightChild);} }二叉排序樹的性能分析
? ? ?對于每一棵特定的二叉排序樹,均可按照平均查找長度的定義來求它的?ASL?值,顯然,由值相同的?n?個關鍵字,構造所得的不同形態的各棵二叉排序樹的平均查找長度的值不同,甚至可能差別很大(如果二叉查找樹退化成一條鏈表,?則其插入/刪除/查找的性能都會退化為O(N))。
? ? ?但是在隨機情況下,?二叉排序樹的搜索,?插入,?刪除操作的平均時間代價為O(logN);
總結
以上是生活随笔為你收集整理的数据结构基础(17) --二叉查找树的设计与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Master Data Service调
- 下一篇: 输入法——讨厌的全角