搜索结构之二叉搜索树:
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
二叉搜索树的实现递归和非递归:
BSTree.h
#pragma once //二叉搜索树---左子树比根节点小,右子树比根节点大,中序遍历时可得到升序序列 typedef int DataType; typedef struct BSTreeNode{ struct BSTreeNode* _pLeft; struct BSTreeNode* _pRight; DataType _data; }BSTreeNode; void InitBSTree(BSTreeNode**pRoot); void InsertBSTree(BSTreeNode**pRoot, DataType data); int FindBSTree(BSTreeNode*pRoot, DataType data); void DeleteBSTree(BSTreeNode**pRoot, DataType data); void PreOrder(BSTreeNode* pRoot); void DestroyBSTree(BSTreeNode**pRoot); int DG_FindBSTree(BSTreeNode*pRoot, DataType data); void DG_InsertBSTree(BSTreeNode**pRoot, DataType data); void DG_DeleteBSTree(BSTreeNode**pRoot, DataType data);
BSTree.c
#include "BSTree.h" #include<assert.h> #include<stdlib.h> #include<stdio.h> #include<malloc.h> void InitBSTree(BSTreeNode**pRoot){ assert(pRoot); *pRoot = NULL; } BSTreeNode* BuyBSTreeNode(DataType data){ BSTreeNode * NewNode = (BSTreeNode *)malloc(sizeof(BSTreeNode)); if (NewNode == NULL) return NULL; NewNode->_data = data; NewNode->_pLeft = NULL; NewNode->_pRight = NULL; return NewNode; } void InsertBSTree(BSTreeNode**pRoot, DataType data){ BSTreeNode *pcur=NULL; BSTreeNode *parent=NULL; assert(pRoot); if (*pRoot == NULL) { *pRoot = BuyBSTreeNode(data); return; } //查找待插节点的位置 pcur = *pRoot; while (pcur) { if (data>pcur->_data) { parent = pcur; pcur = pcur->_pRight; } else if (data < pcur->_data){ parent = pcur; pcur = pcur->_pLeft; } else return; } //插入新节点 pcur = BuyBSTreeNode(data); if (data<(parent->_data)) parent->_pLeft=pcur; else parent->_pRight = pcur; } int FindBSTree(BSTreeNode*pRoot, DataType data){ BSTreeNode *pcur = pRoot; while (pcur) { if (data == pcur->_data) return 1; else if (data<pcur->_data) pcur = pcur->_pLeft; else pcur = pcur->_pRight; } return 0; } void DeleteBSTree(BSTreeNode**pRoot, DataType data){ BSTreeNode *pcur = NULL; BSTreeNode *parent = NULL; assert(pRoot); if (0 == FindBSTree(*pRoot,data)) return; pcur = (*pRoot); while (pcur) { if (data>pcur->_data) { parent = pcur; pcur = pcur->_pRight; } else if (data < pcur->_data) { parent = pcur; pcur = pcur->_pLeft; } else break; } //待删元素不在树中 if (pcur == NULL) return; //找到该节点 if (pcur->_pLeft==NULL)//该节点是叶子节点或者是只有右子树 { if (pcur == (*pRoot)) *pRoot = pcur->_pRight; else { if (pcur == parent->_pLeft) parent->_pLeft = pcur->_pRight; else parent->_pRight = pcur->_pRight; } } else if (pcur->_pRight==NULL)//该节点是叶子节点或者是只有左子树 { if (pcur == (*pRoot)) *pRoot = pcur->_pLeft; else { if (pcur == parent->_pLeft) parent->_pLeft = pcur->_pLeft; else parent->_pRight = pcur->_pLeft; } free(pcur); } else// 左右孩子都有,在左子树中寻找最大节点或者在右子树中寻找最小的节点,替换待删节点,然后删除 { BSTreeNode *pDel = pcur->_pRight; parent = pDel; while (pDel->_pLeft) { parent = pDel; pDel = pDel->_pLeft; } pcur->_data = pDel->_data; if (pDel = parent->_pLeft) parent->_pLeft = pDel->_pRight; if (pDel = parent->_pRight) parent->_pRight = pDel->_pRight; } free(pcur); } void PreOrder(BSTreeNode* pRoot){ if (pRoot) { PreOrder(pRoot->_pLeft); printf("%d ", pRoot->_data); PreOrder(pRoot->_pRight); } } void DestroyBSTree(BSTreeNode**pRoot){ assert(pRoot); if (*pRoot) { DestroyBSTree(&(*pRoot)->_pLeft); DestroyBSTree(&(*pRoot)->_pRight); free(*pRoot); *pRoot = NULL; } } //递归 int DG_FindBSTree(BSTreeNode*pRoot, DataType data){ if (NULL == pRoot) return 0; if (data == pRoot->_data) return 1; else if(data < pRoot->_data) return DG_FindBSTree(pRoot->_pLeft,data); else return DG_FindBSTree(pRoot->_pRight,data); } void DG_InsertBSTree(BSTreeNode**pRoot, DataType data){ assert(pRoot); if (*pRoot == NULL) { *pRoot = BuyBSTreeNode(data); return; } else { if (data < (*pRoot)->_data) return DG_InsertBSTree(&(*pRoot)->_pLeft, data); else if (data > (*pRoot)->_data) return DG_InsertBSTree(&(*pRoot)->_pRight, data); else return; } } void DG_DeleteBSTree(BSTreeNode**pRoot, DataType data){ assert(pRoot); if (*pRoot == NULL) { return; } if (data < (*pRoot)->_data) return DG_DeleteBSTree(&(*pRoot)->_pLeft, data); else if (data >(*pRoot)->_data) return DG_DeleteBSTree(&(*pRoot)->_pRight, data); else { BSTreeNode *pDel = *pRoot; if (pDel->_pLeft == NULL){ *pRoot = pDel->_pRight; free(pDel); } else if (pDel->_pRight == NULL){ *pRoot = pDel->_pLeft; free(pDel); } else{ BSTreeNode *pDel = (*pRoot)->_pRight; while (pDel->_pLeft) pDel = pDel->_pLeft; (*pRoot)->_data = pDel->_data; return DG_DeleteBSTree(&(*pRoot)->_pRight, data); } } }
二叉搜索树的性能分析:
二叉搜索树的插入和删除都必须先查找,查找的效率代表了二叉搜索树中各个操作的性能.
对于有n个节点的二叉搜索树,最优情况下,二叉树为完全二叉树,其平均比较的次数就是lgN.最差情况下,二叉树为单支树,其平均比较的次数就是N/2.
如果退化成单枝树,二叉搜索树的性能就消失了,为了使性能更加,需要进行改进!!!
平衡树(解决单支问题):
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下.因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度.
AVL树
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在O(lgn),平均搜索时间复杂度O(lg(n))
红黑树
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似平衡,而且在实际应用中发现红黑树性能确实比AVL树性能高
红黑树性质
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)