二叉搜索树
二叉查找树(Binary Search Tree),(二叉搜索树 或 二叉排序树)它或者是一棵空树,
或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树。
二叉树实现:二叉树及二叉树的基本操作(递归与非递归) - CSDN博客 https://blog.csdn.net/W_J_F_/article/details/80408846
BinarySearchTree.h
#pragma once #include<stdio.h> #include<stdlib.h> #include<malloc.h> #include<assert.h> typedef int DataType; typedef struct BSTreeNode { struct BSTreeNode* _pleft; struct BSTreeNode* _pright; DataType _data; }BSTNode; // 初始化二叉搜索树 void InitBSTree(BSTNode** pRoot); // 插入值为data的元素 void InsertBSTree(BSTNode** pRoot, DataType data); // 删除值为data的结点 void DeleteBSTree(BSTNode** pRoot, DataType data); // 在二叉搜索树中查找值为data的结点 BSTNode* FindBSTree(BSTNode* pRoot, DataType data); // 中序遍历二叉搜索树 void InOrder(BSTNode* pRoot); // 销毁二叉搜索树 void DestroyBSTree(BSTNode** pRoot); ////////////////////////////////////////////////////////// BSTNode* _FindBSTree(BSTNode* pRoot, DataType data); int _InsertBSTree(BSTNode** pRoot, DataType data); int _DeleteBSTree(BSTNode** pRoot, DataType data);
BInarySearchTree.c
#include"BinarySearchTree.h" // 初始化二叉搜索树 void InitBSTree(BSTNode** pRoot)//改变指针的指向传二级指针 { assert(pRoot); *pRoot = NULL; } BSTNode* BuyNode(DataType data) { BSTNode* pNew = (BSTNode*)malloc(sizeof(BSTNode)); if (pNew == NULL) { assert(0); return 0; } pNew->_data = data; pNew->_pleft = NULL; pNew->_pright = NULL; return pNew; } // 插入值为data的元素 void InsertBSTree(BSTNode** pRoot, DataType data) { BSTNode* pParent = NULL; BSTNode* pCur = NULL; assert(pRoot); if (*pRoot == NULL)//如果树是空的 { *pRoot = BuyNode(data); return; } //查找待插入位置 pCur = *pRoot; while (pCur) { if (data < pCur->_data) { pParent = pCur; pCur = pCur->_pleft; } else if (data > pCur->_data) { pParent = pCur; pCur = pCur->_pright; } else { return; } } //插入节点 pCur = BuyNode(data); if (data > pParent->_data) { pParent->_pright = pCur; } else { pParent->_pleft = pCur; } } // 删除值为data的结点 void DeleteBSTree(BSTNode** pRoot, DataType data) { //1:左右孩子为空,直接删除 //2:只有左孩子(1:是否有双亲,2:是双亲的左或右孩子) //3:只有右孩子(1:是否有双亲,2:是双亲的左或右孩子) //4:左右孩子均存在 》》找代替节点 1:左子树代替——最大元素 // 2:右子树代替——最小元素 // 》》将代替节点中的的数据交给待删除的节点 // 》》连接(待删除节点为其双亲的左或右孩子) //找待删除节点在二叉搜索树的位置 BSTNode* pCur = *pRoot; BSTNode* pParent = pCur; while (pCur) { if (data == pCur->_data) break; else if (data > pCur->_data) { pParent = pCur;//记录双亲 pCur = pCur->_pright; } else { pParent = pCur; pCur = pCur->_pleft; } } if (NULL == pCur) return; //删除 if (NULL == pCur->_pleft)//只右有孩子||叶子 { if (pCur == *pRoot)//无双亲 { *pRoot = pCur->_pright; } else { if (pParent->_pleft == pCur)//待删除节点是双亲的左 { pParent->_pleft = pCur->_pright; } else//待删除节点是双亲的右 pParent->_pright = pCur->_pright; } } else if (NULL == pCur->_pright)//只有左孩子||叶子 { if (pCur == *pRoot) { *pRoot = pCur->_pleft; } else { if (pParent->_pleft == pCur) { pParent->_pleft = pCur->_pleft; } else { pParent->_pright = pCur->_pleft; } } } else//左右孩子均存在 { //4:左右孩子均存在 》》找代替节点 1:左子树代替——最大元素 // 2:右子树代替——最小元素 // 》》将代替节点中的的数据交给待删除的节点 // 》》连接(待删除节点为其双亲的左或右孩子) BSTNode* pDel = pCur->_pright; //寻找右子树的最小结点 while (pDel->_pleft) { pParent = pDel; pDel = pDel->_pleft; } pCur->_data = pDel->_data; if (pDel == pParent->_pleft)//待删除节点可能含有右子树(已经找到最左) { pParent->_pleft = pDel->_pright; } else { pParent->_pright = pDel->_pright; pCur = pDel; } } free(pCur); pCur = NULL; } // 在二叉搜索树中查找值为data的结点 BSTNode* FindBSTree(BSTNode* pRoot, DataType data) { assert(pRoot); BSTNode* pCur = pRoot; while (pCur) { if (data == pCur->_data) return pCur; else if (data > pCur->_data) pCur = pCur->_pright; else pCur = pCur->_pleft; } return NULL; } // 中序遍历二叉搜索树 void InOrder(BSTNode* pRoot) { if (pRoot) { InOrder(pRoot->_pleft); printf("%d->",pRoot->_data); InOrder(pRoot->_pright); } } // 销毁二叉搜索树 void DestroyBSTree(BSTNode** pRoot) { assert(pRoot); if (*pRoot) { DestroyBSTree(&(*pRoot)->_pleft); DestroyBSTree(&(*pRoot)->_pright); free(*pRoot); *pRoot = NULL; } } ////////////////////////////////////递归 BSTNode* _FindBSTree(BSTNode* pRoot, DataType data) { if (pRoot == NULL) { return NULL; } else { if (data == pRoot->_data) { return pRoot; } else if (data > pRoot->_data) { return _FindBSTree(pRoot->_pleft,data); } else { return _FindBSTree(pRoot->_pright,data); } } } int _InsertBSTree(BSTNode** pRoot, DataType data) { assert(pRoot); if (NULL == *pRoot) { *pRoot = BuyNode(data); } else { if (data > (*pRoot)->_data) { _InsertBSTree(&(*pRoot)->_pright, data); } else if (data < (*pRoot)->_pleft) { _InsertBSTree(&(*pRoot)->_pright, data); } else { return 0; } } } int _DeleteBSTree(BSTNode** pRoot, DataType data) { assert(pRoot); if (NULL == *pRoot) { return 0; } else { if (data > (*pRoot)->_data) { _DeleteBSTree(&(*pRoot)->_pright,data); } else if (data < (*pRoot)->_data) { _DeleteBSTree(&(*pRoot)->_pleft,data); } else { //只有右孩子||叶子节点 BSTNode* pDel = *pRoot; if (NULL == pDel->_pleft) { *pRoot = pDel->_pright; free(pDel); } else if(NULL == pDel->_pright)//只有左子树||叶子 { *pRoot = pDel->_pleft; free(pDel); } else//左右子树 { pDel = (*pRoot)->_pright; while (pDel->_pleft) { pDel->_pleft; } (*pRoot)->_data = pDel->_data; _DeleteBSTree(&(*pRoot)->_pright,pDel->_data); } } } }
test
#include"BinarySearchTree.h" test() { int a[] = {5,4,6,9,0,2,1,8,7,3}; int i = 0; BSTNode* pRoot; InitBSTree(&pRoot); for (;i < sizeof(a) / sizeof(a[0]);i++) { InsertBSTree(&pRoot,a[i]); } printf("InOrder: "); InOrder(pRoot); printf("\n"); DeleteBSTree(&pRoot, 5); printf("InOrder: "); InOrder(pRoot); printf("\n"); DeleteBSTree(&pRoot, 7); printf("InOrder: "); InOrder(pRoot); printf("\n"); } int main() { test(); system("pause"); return 0; }
二叉搜索树性能分析:
二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:
////////////////////////////////////////
AVL树
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结
点,其高度可保持在O(lgn),平均搜索时间复杂度O(lg(n))
红黑树:
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,
可以是red或者black,通过对任何一条从根节点到叶子结点简单路径上的颜色来约束,
红黑树保证最长路径不超过最短路径的两倍,
因而近似平衡,而且在实际应用中发现红黑树性能确实比AVL树性能高
红黑树性质:
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)