给出二叉搜索树的定义:
typedef char SearchTreeType; typedef struct SearchTreeNode { SearchTreeType key; // 关键码 struct SearchTreeNode* lchild; struct SearchTreeNode* rchild; }SearchTreeNode;
将函数的声明放在head.h的头文件里面:
#pragma once #include <stdio.h> #include <windows.h> typedef char SearchTreeType; typedef struct SearchTreeNode { SearchTreeType key; // 关键码 struct SearchTreeNode* lchild; struct SearchTreeNode* rchild; }SearchTreeNode; // 初始化 void SearchTreeInit(SearchTreeNode** root); // 创建新节点 SearchTreeNode* CreateSearchTreeNode(SearchTreeType key); //非递归 // 插入 void SearchTreeInsert_P(SearchTreeNode** root, SearchTreeType key); // 查找 SearchTreeNode* SearchTreeFind_P(SearchTreeNode* root, SearchTreeType to_find); // 删除 void SearchTreeRemove_P(SearchTreeNode** root, SearchTreeType key); void PreOrder(SearchTreeNode* root); void InOrder(SearchTreeNode* root); void DestroySearchTreeNode(SearchTreeNode* node); //递归 // 插入 void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key); // 查找 SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find); // 删除 void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key);
函数的定义(具体实现):
#include "SearchTree.h" void SearchTreeInit(SearchTreeNode** root) { if (root == NULL) { return; } *root = NULL; } void DestroySearchTreeNode(SearchTreeNode* node) { free(node); } SearchTreeNode* CreateSearchTreeNode(SearchTreeType key) { SearchTreeNode* new_node = (SearchTreeNode*)malloc(sizeof(SearchTreeNode)); new_node->key = key; new_node->lchild = NULL; new_node->rchild = NULL; return new_node; } void SearchTreeInsert_P(SearchTreeNode** root, SearchTreeType key) { if (root == NULL) { return; } // 1. 如果这个树是空树 if (*root == NULL) { *root = CreateSearchTreeNode(key); return; } // 2. 如果这个树是非空树: // a) 先查找到一个合适的插入位置 SearchTreeNode* cur = *root; SearchTreeNode* parent = NULL; while (1) { if (cur == NULL) { // 合适的位置已经找到了 break; } if (key < cur->key) { parent = cur; cur = cur->lchild; } else if (key > cur->key) { parent = cur; cur = cur->rchild; } else { // 发现当前元素和要插入的值相同,此处我们约定,让其插入失败 return; } } // b) 再在对应的位置上创建结点 SearchTreeNode* new_node = CreateSearchTreeNode(key); if (key < parent->key) { parent->lchild = new_node; } else { parent->rchild = new_node; } } SearchTreeNode* SearchTreeFind_P(SearchTreeNode* root, SearchTreeType to_find) { if (root == NULL) { return; } SearchTreeNode* cur = root; while (cur) { if (to_find < cur->key) { cur = cur->lchild; } else if (to_find < cur->key) { cur = cur->rchild; } else { break; } } return cur; } void SearchTreeRemove_P(SearchTreeNode** root, SearchTreeType key) { if (root == NULL) { return; } // 1. 处理空树的情况,直接返回 if (*root == NULL) { return NULL; } // 2. 找到要删除的结点的位置,以及要删除结点的父节点 SearchTreeNode* to_remove = *root; SearchTreeNode* parent = NULL; while (to_remove) { if (key < to_remove->key) { parent = to_remove; to_remove = to_remove->lchild; } else if (key > to_remove->key) { parent = to_remove; to_remove = to_remove->rchild; } else { // 找到了 break; } } // 3. 如果要查找元素在树中没有找到,也直接返回 if (to_remove == NULL) { return; } // 4. 如果要删除的结点存在,要分情况讨论: // a) 要删除的结点,没有子树,直接删除该结点,并且将父节点置空 if (to_remove->lchild == NULL && to_remove->rchild == NULL) { if (to_remove == *root) { // 如果要删除的元素是根节点,那么就直接处理 *root = NULL; } else { // 如果要删除的元素不是根节点,按以下逻辑判定 if (parent->lchild == to_remove) { parent->lchild = NULL; } else { parent->lchild = NULL; } } DestroySearchTreeNode(to_remove); return; } // b) 要删除的结点,只有左子树,删除该结点同时,将该结点的左子树挂到父节点上 else if (to_remove->lchild != NULL && to_remove->rchild == NULL) { if (to_remove == *root) { // 如果要删除的元素是根节点 *root = to_remove->lchild; } else { // 如果要删除的元素不是根节点,按以下逻辑判定 if (to_remove == parent->lchild) { parent->lchild = to_remove->lchild; } else { parent->rchild = to_remove->lchild; } } DestroySearchTreeNode(to_remove); return; } // c) 要删除的结点,只有右子树,删除该结点同时,将该结点的右子树挂到父节点上 else if (to_remove->lchild == NULL && to_remove->rchild != NULL) { if (to_remove == *root) { // 如果要删除的元素是根节点 *root = to_remove->rchild; } else { // 如果要删除的元素不是根节点,按以下逻辑判定 if (to_remove == parent->lchild) { parent->lchild = to_remove->rchild; } else { parent->rchild = to_remove->rchild; } } DestroySearchTreeNode(to_remove); return; } // d) 要删除的结点,同时有左右子树,找到右子树中的最小值,然后将该最小值赋值给要删除的位置, // 然后再删除该右子树中的最小值结点,这样一个结点最多只有一个右子树,就转换成了情况 c) else { SearchTreeNode* min = to_remove->rchild; SearchTreeNode* min_parent = to_remove; while (min->lchild != NULL) { min_parent = min; min = min->lchild; } // 代码执行到这里的时候,min就已经指向 to_remove 右子树的最小值 to_remove->key = min->key; if (min_parent->lchild == min) { min_parent->lchild = min->rchild; } else { min_parent->rchild = min->rchild; } DestroySearchTreeNode(min); return; } } void PreOrder(SearchTreeNode* root) { if (root) { printf("%c ", root->key); PreOrder(root->lchild); PreOrder(root->rchild); } } void InOrder(SearchTreeNode* root) { if (root) { InOrder(root->lchild); printf("%c ", root->key); InOrder(root->rchild); } } void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key) { if (root == NULL) { // 非法输入 return; } if (*root == NULL) // 关键代码 // 2. 创建新的结点,挂在对应的位置上 { *root = CreateSearchTreeNode(key); return; } // 1. 先找到要往哪个位置插入 if (key < (*root)->key) { SearchTreeInsert(&(*root)->lchild, key); } else if (key > (*root)->key) { SearchTreeInsert(&(*root)->rchild, key); } else { // 发现当前元素和要插入的值相同,此处我们约定,让其插入失败 return; } } SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find) { if (root == NULL) { // 空树 return; } if (to_find < root->key) { return SearchTreeFind(root->lchild, to_find); } else if (to_find > root->key) { return SearchTreeFind(root->rchild, to_find); } else { // 找到 return root; } } void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key) { if (root == NULL) { // 非法输入 return; } // 1. 找到要删除的元素在树中的位置 // 2. 如果没找到的话,不需要进行任何删除操作 if (*root == NULL) { // 空树 return; } if (key < (*root)->key) { SearchTreeRemove(&(*root)->lchild, key); } else if (key > (*root)->key) { SearchTreeRemove(&(*root)->rchild, key); } // 3. 如果找到了的话,分情况来讨论 else { SearchTreeNode* to_remove = *root; // a) 要删除元素没有子树,直接删除该结点就行了 if (to_remove->lchild == NULL && to_remove->rchild == NULL) { *root = NULL; DestroySearchTreeNode(to_remove); } // b) 要删除元素只有左子树,先把左子树挂在父节点上,再删除当前结点 else if (to_remove->lchild != NULL && to_remove->rchild == NULL) { *root = to_remove->lchild; DestroySearchTreeNode(to_remove); } // c) 要删除元素只有右子树,先把右子树挂在父节点上,再删除当前结点 else if (to_remove->lchild == NULL && to_remove->rchild != NULL) { *root = to_remove->rchild; DestroySearchTreeNode(to_remove); } // d) 要删除元素同时有左右子树,先找到当前元素右子树中最小的那个元素, // 把这个最小元素赋值到要删除的元素上,然后再删除刚才的最小元素,然后把问题转换成 b) 或者 c) else { SearchTreeNode* min = to_remove->rchild; while (min->lchild != NULL) { min = min->lchild; } // 代码执行到这里,意味着 min 已经指向了 to_remove 的右子树中的最小元素 to_remove->key = min->key; SearchTreeRemove(&to_remove->rchild, min->key); } // to_remove 左右子树都存在 } // key == to_remove->key }
测试代码:
#include "SearchTree.h" void TestSearchTree() { SearchTreeNode* root; SearchTreeInit(&root); printf("root expect NULL, actual %p\n", root); SearchTreeInsert_P(&root, 'B'); SearchTreeInsert_P(&root, 'A'); SearchTreeInsert_P(&root, 'G'); SearchTreeInsert_P(&root, 'D'); SearchTreeInsert_P(&root, 'E'); SearchTreeInsert_P(&root, 'F'); printf("先序遍历:"); PreOrder(root); printf("\n"); printf("中序遍历:"); InOrder(root); printf("\n"); SearchTreeNode* result = SearchTreeFind(root, 'E'); printf("result expect %p, actual %p \n", root->rchild->lchild->rchild, result); } int main() { TestSearchTree(); system("pause"); return 0; }
结果如下: