C++10.3 查找第 k 小元素10.4 二叉排序树①

本文介绍了C++中查找第k小元素的算法,通过对比快速排序,提出在特定情况下可以达到线性级别的效率。此外,详细讲解了二叉排序树的概念、插入元素、删除元素以及查找元素的操作,强调了二叉排序树保持中序遍历顺序的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

10.3 查找第 k 小元素!

10.4 二叉排序树①

(1) 二叉排序树

(2) 插入一个元素

(3) 删除一个元素*

(4) 查找一个元素


10.3 查找第 k 小元素!

和快速排序相近。不同的是,在“递归”这一阶段只需对“有第 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 不太大,可以用堆(优先队列)解决。

10.4 二叉排序树①

(1) 二叉排序树

二叉排序树的两个重要性质:
 设 R 为任意结点,则 R 的左儿子<R,R 的右儿子≥R。(如果你需要,可以把不等号的方向调换一下)
 对二叉排序树进行中序遍历,得到的一定是从小到大排好的结果。
在本节,二叉树使用一般的定义方法,即之前的 struct node。

(2) 插入一个元素

插入时从顶端的根结点开始。假设插入的值为 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;
}

(3) 删除一个元素*

删除的难点在于删除某一个结点之后,必须保持二叉排序树的性质。解决这个问题的最简单办法是用另外一个数来替换被删除的数,说得具体一点,就是用右子树中的最小值来替换被删除的值。

// 删除最小值(查找最小值,只需一路向左)。
// 注意:这个最小值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;
}

(4) 查找一个元素

和插入的过程类似。如果要找的值就是结点,停止;如果要找的值比结点小,就往左走,否则往右走。

// 如果找到了,就返回一个包含结点的指针;如果找不到,就返回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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值