1. 程式人生 > >資料結構: 二叉搜尋樹

資料結構: 二叉搜尋樹

二叉搜尋樹

二叉查詢樹(Binary Search Tree),也稱二叉搜尋樹、有序二叉樹(ordered binary tree),排序二叉樹(orted binary tree)

特點:

  • 二叉樹
  • 若任意節點的左子樹不空,則左子樹上所有節點的值均小於它的根節點的值
  • 若任意節點的右子樹不空,則右子樹上所有節點的值均大於它的根節點的值
  • 任意節點的左,右子樹也分別為二叉查詢樹
  • 沒有鍵值相等的節點

注:

  • 必須是完全二叉樹
  • 二叉搜尋樹不一定是完全二叉樹

優勢

二叉搜尋相比其他資料結構在查詢和插入的複雜度較低. 均為 O(logN).

它是基礎的資料結構,可用於構建更抽象的資料結構,如集合,對映等.

常用操作

0. 定義:

用一個根節點表示一個二叉搜尋樹

節點的結構如下所示:

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 *root;
	int count;
public:
	BST() {
		root = NULL;
		count = 0;
	}
	~BST() {
		// TODO:
	}
}

1. 查詢

在二叉搜尋樹 root 中查詢 key 是否存在

bool  contains(Node* node, Key key) {
    if (node == NULL)
        return NULL;

    if (node->key > key) {
        return contains(node->left, key);
    }
    else if (node->key < key) {
        return contains(node->right, key);
    }
    else {
        return true;
    }
}

2.插入

插入和查詢是一樣的

// 將(key,value)插入二叉搜尋樹中,返回根節點
Node* insert(Key key,Value value) {
    root = insert(root, key,value);
    return root;
}
Node* insert(Node *node, Key key, Value value) {
    if (node == NULL) {
        count++;
        root = new Node(key, value);
    } else {
        if (key == node->key) {
            node->value = value;
        }
        else if (key > node->key) {
            node->right = insert(node->right,key,value);
        } 
        else{
            // key < node->key
            node->left = insert(node->left, key, value);
        }
    }
    return node;
}

3. 刪除

刪除分為3種情況:

  • 只有左孩子,則將左孩子返回
  • 只有右孩子,則將右孩子返回
  • 左右孩子都有,找到這個節點的後繼節點,再刪除右子樹中的最小節點.將後繼節點的左孩子指向當前的左孩子.然後返回後繼節點.
// 將關鍵字為key的節點,返回根節點
Node* delete(Key key) 		{
    root = delete(root, key);
}
// 
Node* delete(Node* node, Key key) {
    if (node == NULL) {
        return NULL;
    }
    if (node->key < key) {
        // 在左子樹中刪除,返回根節點的左孩子
        node->left = delete(node->left, key);
        return node;
    }
    else if (node->key > key) {
        // 在右子樹中刪除,返回根節點的右孩子
        node->right = delete(node->right, key);
        return node;
    }
    else {// 找到了該節點
        // 若左孩子為空,那麼則返回其右孩子
        if (node->left == NULL) {
            Node* rightNode = node->right;
            node->right = NULL;
            size--;
            return rightNode;
        }
        // 若右孩子為空,那麼則返回其左孩子
        else if (node->right == NULL) {
            Node* leftNode = node->left;
            node->left = NULL;
            size--;
            return leftNode;
        }
        else {
            // 如果二者都不為空,在右子樹找最小值結點,即後繼節點
            Node* successor = minimum(node->right);
            // 將這個最小值結點刪除
            successor->right = deleteMin(node->right);
            // 將原來節點的左子樹付給它
            successor->left = node->left;
            // 刪除Node
            node->left = node->right = NULL;
            // 返回這個節點
            return successor;
        }
    }
}
// 遞迴找最小值節點
Node* minimum(Node* node) {
    if (node->left == NULL){
        return node;
    }
    return minimum(node->left);
}
// 遞迴找最大值節點
Node* Maximum(Node* node) {
    if (node->right == NULL) {
        return node;
    }
    return Maximum(node->right);
}
Node* deleteMin(Node* node) {
    if (node->left == NULL) {
        Node* rightNode = node->right;
        node->right = NULL;
        size--;
        return rightNode;
    }
    node->left = deleteMin(node->left);
    return node;
}
Node* deleteMax(Node* node) {
    if (node->right == NULL) {
        Node* leftNode = node->left;
        node->left = NULL;
        size--;
        return leftNode;
    }
    node->right = deleteMin(node->right);
    return node;
}

4.遍歷

中序遍歷有序

參考文獻

二叉搜尋樹詳解與實現