一.二叉搜索树的概念
二叉搜索树又称二叉排序树,他或者是一颗空树,或者具有以下性质的二叉树:
1.若他的左子树不为空,则左子树上的值都小于根结点上的值
2.若他的右子树不为空,则右子树上的值都大于根结点上的值
3.他的左右子树也分别为二叉搜索树
二.二叉搜索树的操作
1.查找
(1.)若根结点不为空且要查找的data == pRoot(根节点的值),则返回ture
(2.)若要查找的data>pRoot(根结点的值),则在他的右子树查找
(3.)若查找的data<pRoot(根结点的值),则在他的左子树查找
如果没找打返回false
2.插入
在二叉树中插入新元素时,必须先检测该元素是否在树中已经存在,如果存在在不进行插入,否则将新元素加入到元素搜索截至的地方。
(1.)若树为空,则直接插入
(2.)树不为空时,按二叉搜索树的性质查找插入位置,插入新节点。
3.删除
(1.)如果没有右孩子或者左右孩子都没有则直接删除
(2.)删除该节点且将被删除节点的双亲结点指向被删除结点的左孩子结点。
(3.)删除该节点且使删除节点的双亲结点指向被删除结点的右孩子结点。
(4.)在他的右子树中寻找中序下的第一个结点(最小结点),用它的值填补到被删除结点中,再来处理该节点的删除问题
左子树中找替代结点----->最右边的结点----->最大的结点
右子树中找替代结点----->最左边的结点----->最小的结点
4.遍历
5.销毁
代码实现
BST.h
#pragma once #include<stdio.h> #include<assert.h> #include<malloc.h> #include<Windows.h> typedef int DataType; typedef struct BSTreeNode { struct BSTreeNode* _pLeft; struct BSTreeNode* _pRight; DataType _data; }BSTNode,*PBSTNode; // 初始化二叉搜索树 void InitBSTree(BSTNode** pRoot); // 插入值为data的元素 void NorInsertBSTree(BSTNode** pRoot, DataType data); // 删除值为data的结点 void NorDeleteBSTree(BSTNode** pRoot, DataType data); // 在二叉搜索树中查找值为data的结点 BSTNode* NorFindBSTree(BSTNode* pRoot, DataType data); // 中序遍历二叉搜索树 void PreOrder(BSTNode* pRoot); // 销毁二叉搜索树 void DestroyBSTree(BSTNode** pRoot); // 递归实现二叉搜索树中查找、插入和删除方法 // 以递归方式实现二叉搜索树 BSTNode* FindBSTree(BSTNode* pRoot, DataType data); void InsertBSTree(BSTNode** pRoot, DataType data); void DeleteBSTree(BSTNode** pRoot, DataType data);
BST.c
#include"bst.h" // 初始化二叉搜索树 void InitBSTree(PBSTNode* pRoot) { assert(pRoot); *pRoot = NULL; } //创建新节点 PBSTNode BuyNewNode(DataType data) { PBSTNode pcur = NULL; pcur = (PBSTNode)malloc(sizeof(BSTNode)); if (NULL == pcur) { printf("申请失败!!"); return 0; } pcur->_data = data; pcur->_pLeft = NULL; pcur->_pRight = NULL; return pcur; } // 插入值为data的元素 void NorInsertBSTree(PBSTNode* pRoot, DataType data) { PBSTNode pcur = *pRoot; PBSTNode parent = NULL; if (NULL == *pRoot) { *pRoot = BuyNewNode(data); return; } while (pcur) { //向左插入 if (pcur->_data > data) { parent = pcur; pcur = pcur->_pLeft; } //向右插入 else if (pcur->_data < data) { parent = pcur; pcur = pcur->_pRight; } //数据相等 else return; } if (data > parent->_data) parent->_pRight = BuyNewNode(data); else parent->_pLeft = BuyNewNode(data); } // 中序遍历二叉搜索树 void PreOrder(PBSTNode pRoot) { if (pRoot) { PreOrder(pRoot->_pLeft); printf("%d-->", pRoot->_data); PreOrder(pRoot->_pRight); } } // 删除值为data的结点 void NorDeleteBSTree(PBSTNode* pRoot, DataType data) { PBSTNode pcur = *pRoot; PBSTNode parent = NULL; assert(pRoot); if (NULL == *pRoot) return; //先找到待删除节点 while (pcur) { if (data == pcur->_data) break; else if (data > pcur->_data) { parent = pcur; pcur = pcur->_pRight; } else { parent = pcur; pcur = pcur->_pLeft; } } //如果循环出来pcur为空则没有data值直接返回 if (NULL == pcur) return; else { //如果待删除节点没有右子树或者左右子树都没有则直接删除 if (!(pcur->_pRight)) { if (pcur->_data > parent->_data) parent->_pRight = pcur->_pRight; else parent->_pLeft = pcur->_pLeft; } //如果没有左子树直接删除 else if (!(pcur->_pLeft)) { if (pcur->_data > parent->_data) parent->_pRight = pcur->_pRight; else parent->_pLeft = pcur->_pLeft; } //如果左右子树都在 else { //那就需要找一个替代节点 //1.右子树中-->找最小的节点--->即右子树中最左的节点 //2.左子树中-->找最大的节点--->即左子树中最右的节点 PBSTNode ptr = pcur; parent = pcur; pcur = pcur->_pLeft; while (pcur->_pRight) { parent = pcur; pcur = pcur->_pRight; } //用左子树中最大的节点替换带删除节点 ptr->_data = pcur->_data; //判断代替节点是其双亲的什么节点 //如果是其左节点 if (pcur == parent->_pLeft) parent->_pLeft = pcur->_pRight; else parent->_pRight = pcur->_pRight; } } free(pcur); } // 在二叉搜索树中查找值为data的结点 BSTNode* NorFindBSTree(PBSTNode pRoot, DataType data) { PBSTNode pcur = pRoot; assert(pRoot); if (NULL == pRoot) return 0; while (pcur) { if (data > pcur->_data) { pcur = pcur->_pRight; } else if (data < pcur->_data) { pcur = pcur->_pLeft; } else return pcur; } } // 销毁二叉搜索树 void DestroyBSTree(PBSTNode* pRoot) { assert(pRoot); if (*pRoot) { DestroyBSTree(&(*pRoot)->_pLeft); DestroyBSTree(&(*pRoot)->_pRight); free(*pRoot); (*pRoot)->_data = NULL; } } //递归实现在二叉搜索树种查找一个值 BSTNode* FindBSTree(PBSTNode pRoot, DataType data) { PBSTNode pcur = pRoot; if (NULL == pRoot) return 0; if (data == pcur->_data) return pcur; else if (data > pcur->_data) return FindBSTree(pcur->_pRight, data); else return FindBSTree(pcur->_pLeft, data); } //递归方法插入元素 void InsertBSTree(PBSTNode* pRoot, DataType data) { assert(pRoot); if (NULL == *pRoot) *pRoot = BuyNewNode(data); else if (data > (*pRoot)->_data) InsertBSTree(&(*pRoot)->_pRight, data); else if (data < (*pRoot)->_data) InsertBSTree(&(*pRoot)->_pLeft, data); else return; } //递归方法删除元素 void DeleteBSTree(PBSTNode* pRoot, DataType data) { assert(pRoot); if (NULL == *pRoot) return; else { //如果data大则在右子树中找 if (data > (*pRoot)->_data) DeleteBSTree(&(*pRoot)->_pRight, data); //如果data小则在左子树中找 else if (data < (*pRoot)->_data) DeleteBSTree(&(*pRoot)->_pLeft, data); else { //如果没有右子树或者左右子树都没有 //直接删 BSTNode* pDel = *pRoot; if (!(*pRoot)->_pRight) { *pRoot = pDel->_pLeft; free(pDel); } //如果没有左子树,也直接删 else if (!(*pRoot)->_pLeft) { *pRoot = pDel->_pRight; free(pDel); } //如果左右子树都存在 else { //到*pRoot右子树找最小节点--最左边 pDel = (*pRoot)->_pRight; while (pDel->_pLeft) pDel = pDel->_pLeft; //将代替节点的值交给*pRoot (*pRoot)->_data = pDel->_data; //在*pRoot的右子树删除值为pDel->data的节点 DeleteBSTree(&(*pRoot)->_pRight, pDel->_data); } } } }
test.c
#include"bst.h" void TestBST1() { PBSTNode pRoot; int i = 0; int arr[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 }; int size = sizeof(arr) / sizeof(arr[0]); InitBSTree(&pRoot); for (; i < size;i++) NorInsertBSTree(&pRoot,arr[i]); PreOrder(&(*pRoot)); printf("\n"); NorDeleteBSTree(&pRoot,2); PreOrder(&(*pRoot)); printf("\n"); NorDeleteBSTree(&pRoot, 4); PreOrder(&(*pRoot)); printf("\n"); NorDeleteBSTree(&pRoot, 7); PreOrder(&(*pRoot)); printf("\n"); printf("data = %d ", NorFindBSTree(&(*pRoot), 5)); } #if 0 void TestBST2() { PBSTNode pRoot; int i = 0; int arr[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 }; int size = sizeof(arr) / sizeof(arr[0]); InitBSTree(&pRoot); for (; i < size; i++) InsertBSTree(&pRoot, arr[i]); PreOrder(&(*pRoot)); printf("\n"); DeleteBSTree(&pRoot,2); PreOrder(&(*pRoot)); printf("\n"); } #endif int main() { TestBST1(); //TestBST2(); system("pause"); return 0; }