目录
和快速排序相近。不同的是,在“递归”这一阶段只需对“有第 k 小数据”的一部分进行排序,另一部分就不用管了。理想情况下,该算法的复杂度能达到线性水平。
- int part(int *a, int start, int end)
- {
- int low=start, high=end;
- int temp, check=a[start];
- do
- {
- while (a[high]>=check&&low<high)
- high--;
- if (a[high]<check)
- temp=a[high], a[high]=a[low], a[low]=temp;
- while (a[low]<=check&&low<high)
- low++;
- if (a[low]>check)
- temp=a[high], a[high]=a[low], a[low]=temp;
- }
- while (low!=high);
- a[low]=check;
- return low;
- }
- int find(int *a, int start, int end, int k)
- {
- if (start==end)
- return a[start];
- int p = part(a, start, end);
- int q = p-start+1; // 计算p位置的“排名”
- // 只对包含第k小元素的部分进行查找和排序。
- if (k <= q)
- return find(a, start, p, k);
- else
- return find(a, p+1, end, k-q);
- }
如果 k 不太大,可以用堆(优先队列)解决。
二叉排序树的两个重要性质:
设 R 为任意结点,则 R 的左儿子<R,R 的右儿子≥R。(如果你需要,可以把不等号的方向调换一下)
对二叉排序树进行中序遍历,得到的一定是从小到大排好的结果。
在本节,二叉树使用一般的定义方法,即之前的 struct node。
插入时从顶端的根结点开始。假设插入的值为 a,对于结点 p,如果 a<p,就向左走,否则向右走,直到“无路可走”。
- node * insert(int v, node * p) // 调用方法:head = insert(x, head);
- {
- if (p==NULL)
- {
- NEW(p);
- p->value = v;
- }
- else
- if (v < p->value)
- p->leftchild=insert(v, p->leftchild);
- else
- p->rightchild=insert(v, p->rightchild);
- return p;
- }
删除的难点在于删除某一个结点之后,必须保持二叉排序树的性质。解决这个问题的最简单办法是用另外一个数来替换被删除的数,说得具体一点,就是用右子树中的最小值来替换被删除的值。
- // 删除最小值(查找最小值,只需一路向左)。
- // 注意:这个最小值a要么是叶子,要么只有右儿子。
- // 如果a有右儿子,那么只需把a的右儿子放到a的位置上。
- node * removemin(node * p, int &t) // 调用:head = removeitem(head, x);
- {
- if (p->leftchild == NULL)
- {
- t = p->value;
- return p->rightchild;
- }
- else
- p->leftchild = removemin(p->leftchild, t);
- return p;
- }
- node * removeitem(int value, node * p) // 调用:head = removeitem(x, head);
- {
- if (p==NULL) return NULL;
- if (value < p->value)
- p->leftchild = removeitem(value, p->leftchild);
- else if (value > p->value)
- p->rightchild = removeitem(value, p->rightchild);
- else
- {
- if (p->leftchild == NULL) // 如果只有右儿子,就直接替换
- return p->rightchild;
- else if (p->rightchild == NULL) // 如果只有左儿子,也直接替换
- return p->leftchild;
- else
- p->rightchild = removemin(p->rightchild, p->value);
- }
- return p;
- }
和插入的过程类似。如果要找的值就是结点,停止;如果要找的值比结点小,就往左走,否则往右走。
- // 如果找到了,就返回一个包含结点的指针;如果找不到,就返回NULL。
- node * find(int value, node * p)
- {
- if (p==NULL) return NULL;
- if (value == p->value)
- return p;
- else if (value < p->value)
- return find(value, p->leftchild);
- else
- return find(value, p->rightchild);
- }