首先什么是二叉搜索树?
二叉搜索树又称为二叉排序树,它是一个空树或者具有以下性质:
1)若它的左子树不空,则左子树上的所有节点的值都小于根节点的值
2)
若它的右子树不空,则右子树上的所有节点的值都大于根节点的值
3)它的左右子树也分别为二叉搜索树
由二叉树的定义可以看出它是递归定义的,下面是一些二叉树的基本操作的递归实现:
typedef int DataType; typedef struct BSTreeNode { struct BSTreeNode *pLeft; struct BSTreeNode *pRight; DataType _data; }BSTreeNode; //插入结点递归 void InsertBSTree(BSTreeNode **pRoot, DataType data) { assert(pRoot); if (NULL == *pRoot) *pRoot = BuyBSTNode(data); else { //若根节点的值大于插入结点的值,就插入到左子树中 if ((*pRoot)->_data > data) InsertBSTree(&(*pRoot)->pLeft, data); //若根节点的值小于插入结点的值,就插入到右子树中 else if ((*pRoot)->_data < data) InsertBSTree(&(*pRoot)->pRight, data); else return; } } //删除结点---递归 void DeleteBSTree(BSTreeNode **pRoot, DataType data) { assert(pRoot); if (NULL == *pRoot) return; //在左子树中删除 if ((*pRoot)->_data > data) DeleteBSTree(&(*pRoot)->pLeft, data); //在右子树中删除 else if ((*pRoot)->_data < data) DeleteBSTree(&(*pRoot)->pRight, data); //删除根节点 else { BSTreeNode *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 = pDel->pLeft; (*pRoot)->_data = pDel->_data; DeleteBSTree(&(*pRoot)->pRight, pDel->_data); } } } //找树中是否有此结点 //递归 int FindBSTNode(BSTreeNode *pRoot, DataType data) { if (NULL == pRoot) return 0; if (pRoot->_data > data) return FindBSTNode(pRoot->pLeft, data); else if (pRoot->_data < data) return FindBSTNode(pRoot->pRight, data); else return 1; } //销毁二叉搜索树 void DestroyBSTree(BSTreeNode **pRoot) { assert(pRoot); if (*pRoot) { DestroyBSTree(&(*pRoot)->pLeft); DestroyBSTree(&(*pRoot)->pRight); free(*pRoot); *pRoot = NULL; } }
对于删除结点,插入结点和在二叉搜索树中查找结点也有非递归的实现,如下:
//插入结点 //非递归 void InsertBSTreeNor(BSTreeNode **pRoot, DataType data) { assert(pRoot); if (NULL == *pRoot) *pRoot = BuyBSTNode(data); //找插入结点的位置 BSTreeNode* pCur = *pRoot; BSTreeNode* pParent=NULL; while (pCur) { if (pCur->_data > data) { pParent = pCur; pCur = pCur->pLeft; } else if (pCur->_data < data) { pParent = pCur; pCur = pCur->pRight; } else return; } //进行插入 pCur = BuyBSTNode(data); if (pParent->_data > pCur->_data) pParent->pLeft = pCur; else pParent->pRight = pCur; } //删除结点 //非递归 void DeleteBSTreeNor(BSTreeNode **pRoot, DataType data) { assert(pRoot); //1.查找删除结点的位置 BSTreeNode *pCur = *pRoot; BSTreeNode *pParent = *pRoot; while (pCur) { if (pCur->_data > data) { pParent = pCur; pCur = pCur->pLeft; } else if (pCur->_data < data) { pParent = pCur; pCur = pCur->pRight; } else break; } //待删除结点不在树中 if (pCur == NULL) return; //待删除结点在树中 //2.删除 //(1)待删除结点只有右孩子或者为叶子结点 if (pCur->pLeft == NULL) { //1)待删除结点为根 if (pCur == *pRoot) *pRoot = pCur->pRight; //2)待删除结点不是根 else { //若待删除的结点为左子树,则父结点的左指针指向待删除结点的孩子 if (pCur == pParent->pLeft) pParent->pLeft = pCur->pRight; else pParent->pRight = pCur->pRight; } } //(2)待删除结点只有左孩子 else if (pCur->pRight == NULL) { //1)待删除结点为根 if (pCur == *pRoot) *pRoot = pCur->pLeft; //2)待删除结点不是根 else { //若待删除的结点为左子树,则父结点的左指针指向待删除结点的孩子 if (pCur == pParent->pLeft) pParent->pLeft = pCur->pLeft; else pParent->pRight = pCur->pLeft; } } //(3)待删除结点左右孩子都有 else { //1)找待删除结点左子树的最右边结点或者右子树的最左边结点 BSTreeNode *pDel = pCur->pRight; pParent = pCur;//若pCur没有左子树,pParent就不会更新 while (pDel->pLeft) { pParent = pDel; pDel = pDel->pLeft; } //2)将pDel的值赋给pCur pCur->_data = pDel->_data; //3)删除pDel,此时pDel只有右子树或者为叶子结点 if (pDel == pParent->pLeft) pParent->pLeft = pDel->pRight; else pParent->pRight = pDel->pRight; pCur = pDel; } free(pCur); pCur = NULL; } //找树中是否有此结点 //非递归 int FindBSTNodeNor(BSTreeNode *pRoot, DataType data) { BSTreeNode *pCur = pRoot; while (pCur) { if (pCur->_data == data) return 1; else if (pCur->_data > data) pCur = pCur->pLeft; else pCur = pCur->pRight; } return 0; }
二叉搜索树的性能:
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:logN
最差情况下,二叉搜索树退化为单支数,其平均比较次数为:N/2
因此有AVL树和红黑树:
AVL树:一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:1)它的左右子树都是AVL树 2)左右子树高度之差(平衡因子)的绝对值不超过1(-1、1、0)
AVL树的平均搜索时间为O(logN),避免了二叉搜索树最差的情况。
红黑树:比AVL树性能高,红黑树最长路径不超过最短路径的两倍
红黑树性质:1)每个节点不是红色就是黑色
2)根结点是黑色
3)不可能有连在一起的红色结点
4)对于每个结点,从该结点到其所有后代叶节点的简单路径上,均包含相同数目的黑色结点
5)每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
如图: