在数据的查找这个问题上,如果查找的数据集是有序线性表,并且是顺序存储的,查找可以使用折半、插值、斐波那契等查找算法实现,可惜,因为有序,在插入和删除操作上,就需要耗费大量的时间。
那么有没有一种可以使得插入和删除的效率不错,又可以比较高效地实现查找的算法呢?也就是说有没有一种算法能够使用与动态查找。
动态查找:在查找时插入或者删除的查找表称为动态查找表。
所以就引入了二叉排序树,它是这样的一个二叉树:
- 左子树上的所有结点的值小于它的根结点的值;
- 右子树上的所有结点的值大于它的根结点的值;
- 它的左子树和右子树同样也是一颗二叉排序树。
根据上面的性质可以知道,对这棵二叉排序树中序遍历就得到了一个升序的序列。但是构造一个二叉排序树的目的,并不是为了排序,而是为了提高查找和插入删除的速度。
代码实现
树结构结点定义:
typedef struct BiTNode { int data; struct BiTNode *lchild, *rchild; }BiTNode, *BiTree;
查找实现:查找成功,返回查找到的结点的指针,查找不成功,返回查找路径上最后的一个结点。
//f是当前根结点T的父结点,当查找失败时返回这个父结点 bool SearchBST(BiTree T, int key, BiTree f, BiTree *p) { if (T == NULL) //递归查找不成功 { *p = f; return false; } if (T->data == key) //查找成功 { *p = T; return true; } else if (key < T->data) { return SearchBST(T->lchild, key, T, p); //左子树递归查找 } else { return SearchBST(T->rchild, key, T, p); //右子树递归查找 } }
这里为什么要返回查找路径上的最后一个结点:因为在插入操作的时候,也需要用到查找,而插入的点正好是查找路径上的最后一个结点也就是把要插入的结点作为这个最后结点的孩子。
//插入新结点的时候,要先查找,找到应该插入的位置 bool InsertBST(BiTree *T, int key) { BiTree p, s; if (!SearchBST(*T, key, NULL, &p)) //查找不成功,可以插入 { s = (BiTNode*)malloc(sizeof(BiTNode)); s->data = key; s->lchild = s->rchild = NULL; if (p == NULL) { *T = s; } else if(p->data > key) { p->lchild = s; } else { p->rchild = s; } return true; } else //查找成功,要插入的元素已经存在,插入失败 { return false; } }
时间: 2024-10-18 03:44:06