查找(2)---二分查找

二分查找(基于有序数组)

二分查找的具体步骤:

1.求取数组长中间数;

2.比较查找键(key)和中间键(mid->key),

1)如果key大,则选择数组后半部分,

2)如果key小,则选择数组前半部分,

3)相等,则输出值,结束查找;

3.返回选择的数组继续前两步;

4.如果没有找到键,返回键应该存在的位置。


很明显可以看出二分查找需要数组有序做为前提,所以在符号表中必然会有排序函数。

同时我们使用数组的原因是,数组能够减少每次查找所需的比较次数,且我们可以通过数组标识来快速锁定中间数和查找范围。


二分查找代码:

1.符号表(基于有序数组)

class ST
{
private:
	vector<string> keys;
	vector<string> datas;
public:
	bool Empty(){ return size() == 0 ? 1 : 0; }
	int size(){ return keys.size(); }
};

2.查找

string get(string key)//查找
	{
		if (Empty())return "No key";
		int i = rank(key);
		if (i < size() && keys[i] == key)
			return datas[i];
		return "No key";
	}

1)二分查找递归形式

	int rank(string key){ return rank(key, 0, size() - 1); }
	int rank(string key, int lo, int hi)
	{//二分查找
		if (hi < lo)return lo;//没有键值,返回他应该存在的位置
		int mid = lo + (hi - lo) / 2;
		if (key < keys[mid])return rank(key, lo, mid - 1);
		else if (key > keys[mid])return rank(key, mid + 1, hi);
		else return mid;
	}

2)二分查找迭代形式

int rank(string key)
	{
		int lo = 0, hi = size() - 1;
		while (lo <= hi)
		{
			int mid = lo + (hi - lo) / 2;
			if (key < keys[mid])hi = mid - 1;
			else if (key > keys[mid])lo = mid + 1;
			else return mid;
		}
		return lo;
	}

3.插入

因为二分查找是基于有序数组的,所以我们在插入的时候必须是有序插入。

插入操作分两种情况:

1.是原本存在键值,则替换值

2.是不存在键值,则利用rank函数返回的插入位序,插入元素

1)首先为数组添加新空间

2)返回位序以后的元素全部后移

3)插入元素

void put(string key, string item)//插入
	{
		int i = rank(key), N = size();
		if (i<N && key == keys[i])//如果键存在,直接修改值
		{
			datas[i] = item;
			return;
		}
		keys.push_back(key);//添加新元素
		datas.push_back(item);
		for (int j = N; j > i; j--)//新元素排序
		{//移位方式
			keys[j] = keys[j - 1];
			datas[j] = datas[j - 1];
		}
		keys[i] = key;
		datas[i] = item;
	}

4.删除

删除操作与插入相对应,首先判断删除键值是否存在,存在则移位删除,不存在则返回"No key"。

string delete_1(string key)//删除
	{
		int i = rank(key), N = size();
		if (i < N && keys[i] == key)
		{
			string item = datas[i];
			for (int j = i; j < N - 1; j++)
			{
				keys[j] = keys[j + 1];
				datas[j] = datas[j + 1];
			}
			keys.pop_back();
			datas.pop_back();
			return item;
		}
		return "No key";
	}

5.基于二分查找的其余操作

        string min(){ return keys[0]; }//最小键
	string max(){ return keys[size() - 1]; }//最大键
	string select(int k){ return keys[k]; }//第k个键(从0开始)
	string ceiling(string key)//大于等于key的最小键
	{
		int i = rank(key);
		return keys[i];
	}
	string floor(string key)//小于等于key的最大键
	{
		int i = rank(key);
		return keys[i - 1];
	}
	queue<string> Keys(string lo, string hi)//键的集合
	{
		queue<string> q;
		for (int i = rank(lo); i < rank(hi); i++)
			q.push(keys[i]);
		if (hi == keys[rank(hi)])
			q.push(keys[rank(hi)]);
		return q;
	}

一般情况下二分查找都比顺序查找快得多,他也是众多实际应用程序的最佳选择。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值