1. 程式人生 > >資料結構與演算法C++之二分搜尋樹的刪除節點,刪除任意節點

資料結構與演算法C++之二分搜尋樹的刪除節點,刪除任意節點

上篇部落格介紹了怎樣刪除二分搜尋樹的最大值和最小值節點,下面介紹怎樣刪除樹的任意一個節點
上篇刪除最大值節點的操作,其實刪除的節點要麼沒有左右子節點,要麼只可能有左節點,
同樣,刪除最小值節點的操作,其實刪除的節點要麼沒有左右子節點,要麼只可能有右節點

(1)刪除只有左節點的節點,如刪除節點58,只需要將58刪除掉,然後將其左節點50替換其位置即可
在這裡插入圖片描述

(2)刪除只有右節點的節點,如刪除節點58,只需要將58刪除掉,然後將其右節點60替換其位置即可
在這裡插入圖片描述
(3)刪除既有左節點又有右節點的節點是最複雜的操作,在1962年,Hibbard提出了一種刪除方法,稱為 Habbard Deletion,如下圖所示,如果需要刪除既有左節點又有右節點的節點58(稱為d),那麼需要找出58的右節點中最小的那個節點s,那麼s就是節點59,將節點59放到58的位置即可


在這裡插入圖片描述
具體操作步驟為,首先刪除掉s節點,然後將s節點的右節點指向原來d的右節點60,將s的左節點指向原來d的左節點50
在這裡插入圖片描述
最後就可以徹底刪除節點58了,將節點59作為新的在該位置的節點
在這裡插入圖片描述
下面是刪除節點的程式實現

#include <iostream>
#include <vector>
#include <string>
#include <ctime>  //time()函式
#include <queue>
#include <cassert>
#include "FileOps.h"
using namespace std;
template<typename Key, typename Value> class BST{ private: struct Node{ Key key; Value value; Node *left; Node *right; Node(Key key, Value value){ this->key = key; this->value = value; this->left = this->
right = NULL; } Node(Node *node){ this->key = node->key; this->value = node->value; this->left = node->left; this->right = node->right; } }; Node *root; int count; public: BST(){ root = NULL; count = 0; } ~BST(){ // TODO: ~BST() destroy(root); } int size(){ return count; } bool isEmpty(){ return count == 0; } void insert(Key key, Value value){ root = insert(root, key, value); } bool contain(Key key){ return contain(root, key); } Value *search(Key key){ return search(root, key); } //前序遍歷 void preOrder(){ preOrder(root); } //中序遍歷 void inOrder(){ inOrder(root); } //後序遍歷 void postOrder(){ postOrder(root); } //層序遍歷 void levelOrder(){ quene<Node*> q; q.push(root); while( !q.empty() ){ Node *node = q.front(); q.pop(); cout<<node->key<<endl; if (node->left) q.push(node->left); if (node->right) q.push(node->right); } } //尋找最小的鍵值 Key minimum(){ assert(count != 0); Node* minNode = minimum(root); return minNode->key; } //尋找最大的鍵值 Key maximum(){ assert(count != 0); Node* maxNode = maximum(root); return maxNode->key; } //從二叉樹中刪除最小值所在節點 void removeMin(){ if (root) root = removeMin(root); } //從二叉樹中刪除最大值所在節點 void removeMax(){ if (root) root = removeMax(root); } //從二叉樹中刪除鍵值為key的節點 void remove(Key key){ root = remove(root, key); } private: //向以node為根的二叉搜尋樹中,插入節點(key, value) //返回插入新節點後的二叉搜尋樹的根 //遞迴插入 Node* insert(Node *node, Key key, Value value){ if (node == NULL){ count++; return new Node(key, value); } if(node->key == key) node->value = value; else if (key < node->key) node->left = insert(node->left, key, value); else node->right = insert(node->right, key, value); return node; } //查詢以node為根的二叉搜尋樹中是否包含鍵值為key的節點 bool contain(Node *node, Key key){ if (node == NULL){ return false; } if (key == node->key) return true; else if (key < node->key) return contain(node->left, key); else return contain(node->right, key); } //在以node為根的二叉搜尋樹中查詢key對應的value Value* search(Node *node, Key key){ if (node == NULL) return NULL; if (key == node->key) return &(node->value); else if (key < node->key) return search(node->left, key); else return search(node->right, key); } //對以node為根的二叉搜尋樹進行前序遍歷 void preOrder(Node* node){ if (node != NULL){ cout<<node->key<<endl; preOrder(node->left); preOrder(node->right); } } //對以node為根的二叉搜尋樹進行中序遍歷 void inOrder(Node *node){ if (node != NULL){ inOrder(node->left); cout<<node->key<<endl; inOrder(node->right); } } //對以node為根的二叉搜尋樹進行後序遍歷 void postOrder(Node *node){ if(node != NULL){ postOrder(node->left); postOrder(node->right); cout<<node->key<<endl; } } void destroy(Node *node){ if (node != NULL){ destroy(node->left); destroy(node->right); delete node; count--; } } //在以node為根的二叉搜尋樹中,返回最小鍵值的節點 Node* minimum(Node *node){ if (node->left == NULL) return node; return minimum(node->left); } //在以node為根的二叉搜尋樹中,返回最大鍵值的節點 Node* maximum(Node *node){ if (node->right == NULL) return node; return maximum(node->right); } //刪除掉以node為根的二分搜尋樹中的最小節點 //返回刪除節點後新的二分搜尋樹的根 Node* removeMin(Node* node){ if (node->left == NULL){ Node *rightNode = node->right; delete node; count--; return rightNode; } node->left = removeMin(node->left); return node; } //刪除掉以node為根的二分搜尋樹中的最大節點 //返回刪除節點後新的二分搜尋樹的根 Node* removeMax(Node* node){ if (node->right == NULL){ Node *leftNode = node->left; delete node; count--; return leftNode; } node->right = removeMin(node->right); return node; } //刪除掉以node為根的二分搜尋樹中鍵值為key的節點 //返回刪除節點後新的二分搜尋樹的根 Node* remove(Node *node, Key key){ if(node == NULL) return NULL; if (key < node->key){ node->left = remove(node->left, key); return node; } else if (key > node->key){ node->right = remove(node->right, key); return node; } else{ // key == node->key if (node->left == NULL){ Node *rightNode = node->right; delete node; count--; return rightNode; } if (node->right == NULL){ Node *leftNode = node->left; delete node; count--; return leftNode; } // node->left != NULL && node->right != NULL //Node *delNode = node; Node *successor = new Node(minimum(node->right)); count++; successor->right = removeMin(node->right); successor->left = node->left; //delete delNode; delete node; count--; return successor; } } };

上面刪除既有左節點又有右節點的節點時,使用的是該節點後驅59替代該節點,其實也可以用該節點的前驅53替代該節點。如下圖所示
在這裡插入圖片描述
在這裡插入圖片描述