數據結構學習:二叉查找樹的概念和C語言實現

什麼是二叉查找樹?

二叉查找樹又叫二叉排序樹,縮寫爲BST,全稱Binary Sort Tree或者Binary Search Tree
以下定義來自百度百科:
二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹:

  • 若左子樹不空,則左子樹上所有節點的值均小於它的根節點的值;
  • 若右子樹不空,則右子樹上所有節點的值均大於它的根節點的值;
  • 左、右子樹也分別爲二叉排序樹;
  • 沒有鍵值相等的節點。

二叉查找樹C語言實現

二叉查找樹是將數值比當前節點數值大的優先放到左子樹,數值被當前節點大的放倒右子樹;
C語言要實現以下幾個接口:

  • 查找節點;
  • 插入節點;
  • 刪除節點;

查找節點

  1. 若根結點的關鍵字值等於查找的關鍵字,成功。
  2. 否則,若小於根結點的關鍵字值,遞歸查左子樹。
  3. 若大於根結點的關鍵字值,遞歸查右子樹。
  4. 若子樹爲空,查找不成功。
Positon	search_tree_find(ElementType x, SearchTree root) {
	
	if (root == NULL) {
		return NULL;
	}
	if (x < root->value) {
		root = search_tree_find(x, root->left);
	}
	else if (x < root->value) {
		root = search_tree_find(x, root->right);
	}
	return root;
}

查找最大值

如下圖所示找出最小值只需要遞歸查找右子樹即可;
在這裏插入圖片描述

Positon search_tree_find_max(SearchTree root) {
	if (root == NULL) {
		return NULL;
	}
	if (root->right != NULL) {
		root = search_tree_find_max(root->right);
	}
	return root;
	
}

查找最小值

如下圖所示找出最小值只需要遞歸查找左子樹即可;
在這裏插入圖片描述

Positon search_tree_find_min(SearchTree root) {
	if (root == NULL) {
		return NULL;
	}
	if (root->left != NULL) {
		root = search_tree_find_min(root->left);
	}
	return root;
}

插入節點

插入節點其實和查找節點類似,這裏主要是遞歸得查找需要插入節點的位置,最終將節點插入,search_tree_insert最終會返回一個新的根,如下圖所示,想要將5 插入到圖中左側的樹中,遞歸查找的節點4之後,因爲5大於4,所以需要往右下插入節點,但是傳入的root-right == NULL成立,所以最終分配新節點,並將節點value賦值爲5,然後返回一棵新樹;
在這裏插入圖片描述

SearchTree search_tree_insert(ElementType x, SearchTree root) {	
	//如果是一棵空樹,則新建一棵樹
	if (root == NULL) {
		root = (SearchTree)malloc(sizeof(TreeNodeType));
		if (root == NULL) {
			return NULL;
		}
		root->value = x;
		root->left = NULL;
		root->right = NULL;
		return root;
	}
	if (x < root->value) {
		root->left = search_tree_insert(x, root->left);
	}
	else if (x > root->value) {
		root->right = search_tree_insert(x, root->right);
	}
	return root;
}

刪除節點

節點的刪除,需要判斷三種情況:

  • 需要刪除的是葉子節點(直接刪除節點即可);
  • 刪除的節點只有一個子節點(將父節點值替換爲子節點,然後刪除子節點即可);
  • 刪除的節點有兩個子節點(用該節點右子樹的最小節點來替換當前節點,然後將最小節點刪除即可);

具體如下;刪除情況如下;
1) Node to be deleted is leaf: Simply remove from the tree.

              50                            50
           /     \         delete(20)      /   \
          30      70       --------->    30     70 
         /  \    /  \                     \    /  \ 
       20   40  60   80                   40  60   80

2) Node to be deleted has only one child: Copy the child to the node and delete the child

              50                            50
           /     \         delete(30)      /   \
          30      70       --------->    40     70 
            \    /  \                          /  \ 
            40  60   80                       60   80

3) Node to be deleted has two children: Find inorder successor of the node. Copy contents of the inorder successor to the node and delete the inorder successor. Note that inorder predecessor can also be used.

              50                            60
           /     \         delete(50)      /   \
          40      70       --------->    40    70 
                 /  \                            \ 
                60   80                           80

The important thing to note is, inorder successor is needed only when right child is not empty. In this particular case, inorder successor can be obtained by finding the minimum value in right child of the node.

附錄

search_tree.h

#ifndef SEARCH_TREE
#define SEARCH_TREE

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>

typedef int ElementType;
typedef struct TreeNode TreeNodeType;
typedef TreeNodeType * SearchTree;
typedef TreeNodeType * Positon;

struct TreeNode
{
	ElementType value;
	TreeNodeType *left;
	TreeNodeType *right;
};

SearchTree search_tree_make_empty(SearchTree root);
Positon	search_tree_find(ElementType x, SearchTree root);
Positon search_tree_find_max(SearchTree root);
Positon search_tree_find_min(SearchTree root);
SearchTree search_tree_insert(ElementType x, SearchTree root);
SearchTree search_tree_delete(ElementType x, SearchTree root);
void search_tree_print(SearchTree root);

#ifdef __cplusplus
}
#endif

#endif // !SEARCH_TREE

search_tree.c

#include "search_tree.h"


SearchTree search_tree_make_empty(SearchTree root) {

	if (root != NULL) {
		search_tree_make_empty(root->left);
		search_tree_make_empty(root->right);
	}
	return NULL;
}

Positon	search_tree_find(ElementType x, SearchTree root) {
	
	if (root == NULL) {
		return NULL;
	}
	if (x < root->value) {
		root = search_tree_find(x, root->left);
	}
	else if (x < root->value) {
		root = search_tree_find(x, root->right);
	}
	return root;
}
Positon search_tree_find_max(SearchTree root) {
	if (root == NULL) {
		return NULL;
	}
	if (root->right != NULL) {
		root = search_tree_find_max(root->right);
	}
	return root;
	
}
Positon search_tree_find_min(SearchTree root) {
	if (root == NULL) {
		return NULL;
	}
	if (root->left != NULL) {
		root = search_tree_find_min(root->left);
	}
	return root;
}
SearchTree search_tree_insert(ElementType x, SearchTree root) {
	
	//如果是一棵空樹,則新建一棵樹
	if (root == NULL) {
		root = (SearchTree)malloc(sizeof(TreeNodeType));
		if (root == NULL) {
			return NULL;
		}
		root->value = x;
		root->left = NULL;
		root->right = NULL;
		return root;
	}
	if (x < root->value) {
		root->left = search_tree_insert(x, root->left);
	}
	else if (x > root->value) {
		root->right = search_tree_insert(x, root->right);
	}
	return root;
}

SearchTree search_tree_delete(ElementType x, SearchTree root) {
	
	TreeNodeType *tmpNode = NULL;
	if (root == NULL) {
		return NULL;
	}
	
	if (x < root->value) {
		root->left = search_tree_delete(x, root->left);
	}
	else if (x > root->value) {
		root->right = search_tree_delete(x, root->right);
	}
	else {
		// have two subtrees
		if (root->left && root->right) {
			tmpNode = search_tree_find_min(root->right);
			root->value = tmpNode->value;
			root->right = search_tree_delete(tmpNode->value, root->right);
		}
		// only have one subtree
		else {
			tmpNode = root;
			if (root->left != NULL) {
				root = root->left;				
			}
			if (root->right != NULL) {
				root = root->right;				
			}
			free(tmpNode);
		}
	}
	return root;
}
#define SIZE 50
void search_tree_print(SearchTree root) {
	int head = 0, tail = 0;
	TreeNodeType *p[SIZE] = { NULL };
	TreeNodeType *tmp;
	TreeNodeType *last = root;
	TreeNodeType *nlast = root;
	if (root != NULL) {
		p[head] = root;
		tail++;
		// Do Something with p[head]			
	}
	else {
		return;
	}
	//環形隊列作爲緩衝器
	while (head % SIZE != tail % SIZE) {
		tmp = p[head % SIZE];
		// Do Something with p[head]			
		printf("%d ", tmp->value);
		if (tmp->left != NULL) { // left
			p[tail++ % SIZE] = tmp->left;
			nlast = tmp->left;
		}
		if (tmp->right != NULL) { // right
			p[tail++ % SIZE] = tmp->right;
			nlast = tmp->right;
		}
		if (last == tmp) {
			printf("\n");
			last = nlast;
		}
		head++;
	}
	return;
}

main.cpp

#include <iostream>
#include "search_tree.h"

using namespace std;

int main() {
	SearchTree tmp = NULL;
	SearchTree search_tree = NULL;
	search_tree = search_tree_make_empty(search_tree);
	search_tree = search_tree_insert(50, search_tree);
	search_tree = search_tree_insert(40, search_tree);
	search_tree = search_tree_insert(30, search_tree);
	search_tree = search_tree_insert(60, search_tree);
	search_tree = search_tree_insert(70, search_tree);
	search_tree = search_tree_insert(80, search_tree);

	search_tree_print(search_tree);
	
	tmp = search_tree_find_min(search_tree);
	printf("min value is %d\n", tmp->value);
	printf("address is 0x%08x\n", tmp);
	
	tmp = search_tree_find_max(search_tree);
	printf("max value is %d\n", tmp->value);
	printf("address is 0x%08x\n", tmp);

	search_tree = search_tree_delete(50, search_tree);
	search_tree_print(search_tree);

	search_tree = search_tree_delete(70, search_tree);
	search_tree_print(search_tree);

	getchar();
	return 0;
}

執行結果如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章