Give the definition of a binary search tree:
typedef char SearchTreeType; typedef struct SearchTreeNode { SearchTreeType key; // key code struct SearchTreeNode* lchild; struct SearchTreeNode* rchild; }SearchTreeNode;
Put the function declaration in the head.h header file:
#pragma once #include <stdio.h> #include <windows.h> typedef char SearchTreeType; typedef struct SearchTreeNode { SearchTreeType key; // key code struct SearchTreeNode* lchild; struct SearchTreeNode* rchild; }SearchTreeNode; // initialize void SearchTreeInit(SearchTreeNode** root); // create new node SearchTreeNode* CreateSearchTreeNode(SearchTreeType key); //non-recursive // insert void SearchTreeInsert_P(SearchTreeNode** root, SearchTreeType key); // find SearchTreeNode* SearchTreeFind_P(SearchTreeNode* root, SearchTreeType to_find); // delete void SearchTreeRemove_P(SearchTreeNode** root, SearchTreeType key); void PreOrder(SearchTreeNode* root); void InOrder(SearchTreeNode* root); void DestroySearchTreeNode(SearchTreeNode* node); //recursive // insert void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key); // find SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find); // delete void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key);
Definition of the function (specific implementation):
#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 the tree is empty if (*root == NULL) { *root = CreateSearchTreeNode(key); return; } // 2. If the tree is non-empty: // a) Find a suitable insertion position first SearchTreeNode* cur = *root; SearchTreeNode* parent = NULL; while (1) { if (cur == NULL) { // suitable location has been found break; } if (key < cur->key) { parent = cur; cur = cur->lchild; } else if (key > cur->key) { parent = cur; cur = cur->rchild; } else { // It is found that the current element is the same as the value to be inserted, here we agree to let its insertion fail return; } } // b) Create a node at the corresponding position 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. Handle the case of an empty tree and return directly if (*root == NULL) { return NULL; } // 2. Find the location of the node to be deleted, and the parent node of the node to be deleted 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 { // found it break; } } // 3. If the element you are looking for is not found in the tree, return directly if (to_remove == NULL) { return; } // 4. If the node to be deleted exists, it needs to be discussed according to the situation: // a) The node to be deleted has no subtree, delete the node directly, and leave the parent node empty if (to_remove->lchild == NULL && to_remove->rchild == NULL) { if (to_remove == *root) { // If the element to be deleted is the root node, then process it directly *root = NULL; } else { // If the element to be deleted is not the root node, it is determined by the following logic if (parent->lchild == to_remove) { parent->lchild = NULL; } else { parent->lchild = NULL; } } DestroySearchTreeNode(to_remove); return; } // b) The node to be deleted has only the left subtree. At the same time when the node is deleted, the left subtree of the node is attached to the parent node else if (to_remove->lchild != NULL && to_remove->rchild == NULL) { if (to_remove == *root) { // if the element to delete is the root node *root = to_remove->lchild; } else { // If the element to be deleted is not the root node, it is determined by the following logic if (to_remove == parent->lchild) { parent->lchild = to_remove->lchild; } else { parent->rchild = to_remove->lchild; } } DestroySearchTreeNode(to_remove); return; } // c) The node to be deleted has only the right subtree. At the same time when the node is deleted, the right subtree of the node is attached to the parent node else if (to_remove->lchild == NULL && to_remove->rchild != NULL) { if (to_remove == *root) { // if the element to delete is the root node *root = to_remove->rchild; } else { // If the element to be deleted is not the root node, it is determined by the following logic if (to_remove == parent->lchild) { parent->lchild = to_remove->rchild; } else { parent->rchild = to_remove->rchild; } } DestroySearchTreeNode(to_remove); return; } // d) The node to be deleted has left and right subtrees at the same time, find the minimum value in the right subtree, and then assign the minimum value to the position to be deleted, // Then delete the minimum node in the right subtree, so that a node has at most one right subtree, which is converted into case c) else { SearchTreeNode* min = to_remove->rchild; SearchTreeNode* min_parent = to_remove; while (min->lchild != NULL) { min_parent = min; min = min->lchild; } // When the code is executed here, min already points to the minimum value of the right subtree of 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) { // illegal input return; } if (*root == NULL) // key code // 2. Create a new node and hang it at the corresponding position { *root = CreateSearchTreeNode(key); return; } // 1. First find where to insert if (key < (*root)->key) { SearchTreeInsert(&(*root)->lchild, key); } else if (key > (*root)->key) { SearchTreeInsert(&(*root)->rchild, key); } else { // It is found that the current element is the same as the value to be inserted, here we agree to let its insertion fail return; } } SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find) { if (root == NULL) { // empty tree 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 { // turn up return root; } } void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key) { if (root == NULL) { // illegal input return; } // 1. Find the position in the tree of the element to delete // 2. If not found, no delete operation is required if (*root == NULL) { // empty tree return; } if (key < (*root)->key) { SearchTreeRemove(&(*root)->lchild, key); } else if (key > (*root)->key) { SearchTreeRemove(&(*root)->rchild, key); } // 3. If found, discuss by situation else { SearchTreeNode* to_remove = *root; // a) To delete an element without a subtree, just delete the node directly if (to_remove->lchild == NULL && to_remove->rchild == NULL) { *root = NULL; DestroySearchTreeNode(to_remove); } // b) To delete elements only the left subtree, first hang the left subtree on the parent node, and then delete the current node else if (to_remove->lchild != NULL && to_remove->rchild == NULL) { *root = to_remove->lchild; DestroySearchTreeNode(to_remove); } // c) To delete elements only the right subtree, first hang the right subtree on the parent node, and then delete the current node else if (to_remove->lchild == NULL && to_remove->rchild != NULL) { *root = to_remove->rchild; DestroySearchTreeNode(to_remove); } // d) To delete an element that has left and right subtrees at the same time, first find the smallest element in the right subtree of the current element, // Assign this minimum element to the element to be deleted, then delete the minimum element just now, and then convert the problem into b) or c) else { SearchTreeNode* min = to_remove->rchild; while (min->lchild != NULL) { min = min->lchild; } // The code is executed here, which means that min has pointed to the smallest element in the right subtree of to_remove to_remove->key = min->key; SearchTreeRemove(&to_remove->rchild, min->key); } // to_remove left and right subtrees exist } // key == to_remove->key }
Test code:
#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 traversal: "); PreOrder(root); printf("\n"); printf("Inorder traversal: "); InOrder(root); printf("\n"); SearchTreeNode* result = SearchTreeFind(root, 'E'); printf("result expect %p, actual %p \n", root->rchild->lchild->rchild, result); } intmain() { TestSearchTree(); system("pause"); return 0; }
The result is as follows: