二分查找的改进 差值查找(low<=high,这与快排low

//二分查找的改进,是把原来的mid的计算进行了优化,而非中位数形式;二分查找的(low<=high,这与快排low<high),因为两者意义不同,快排排过的分为点不再排列;二分查找确实需要low=high时的位置。
<pre name="code" class="cpp">#include <iostream>
using namespace std;
const int maxn = 100;
void heap_sort(int arr[],int &len);
void heap_down_adjust(int arr[],int i,int &len);
int bin_search(int arr[],const int &len,const int &k);
int bin_search2(int arr[],const int &len,const int &k);
void my_swap2(int &a,int &b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}
void my_swap(int &a, int &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
int main()
{
    int arr[maxn];
    int tmp,len;
    len = 0;
    cout << "请输入一个序列(-1结束)" << endl;
    while(cin >> tmp)
    {
        if(tmp == -1)
            break;
        arr[len++] = tmp;
    }
    heap_sort(arr,len);
    cout << "请输入一个待查数字(-1结束)" << endl;
    while(cin >> tmp)
    {
        if(tmp == -1)
            break;
        cout << bin_search2(arr,len,tmp) << endl;
    }
}

void heap_sort(int arr[],int &len)
{
    int i;
    for(i=len/2-1; i>=0; --i)// 至于为什么是从i = len/2 -1开始,自己建立一个完全二叉树的数组即可发现规律。
    {
        heap_down_adjust(arr,i,len);
    }// 建立一个初试堆
    //以0 和 len-1为下标的元素交换,之后从0下标开始调整堆,直到剩下一个元素
    for(i=len-1; i>0; --i)
    {
        my_swap(arr[0],arr[i]);
        heap_down_adjust(arr,0,i);// i 代表当前的数组长度
    }
	
}
// 数组,调整位置,数组长度
void heap_down_adjust(int arr[],int i,int &len)
{
    int lc;// 左孩子
    for(; i*2+1<len; i=lc)
    {
        lc = i*2+1;// 从左孩子开始
        if(lc+1<len && arr[lc+1]>arr[lc])//如果右侧孩子大,加一
            lc++;
        if(arr[lc]>arr[i])//较大的孩子节点大于父节点
            my_swap(arr[lc],arr[i]);
        else
            break;//父节点是最大的无需向下调整
    }
}
//int BinSearch(SeqList*R,int n,KeyType K)
int bin_search(int arr[],const int &n,const int &k)
{
	//在有序表R[0..n-1]中进行二分查找,成功时返回结点的位置,失败时返回-1
    int low=0,high=n-1,mid;//置当前查找区间上、下界的初值
    while(low<=high)
    {
        mid=low+((high-low)/2);
        //使用(low+high)/2会有整数溢出的问题
        //(问题会出现在当low+high的结果大于表达式结果类型所能表示的最大值时,
        //这样,产生溢出后再/2是不会产生正确结果的,而low+((high-low)/2)不存在这个问题
        if(arr[mid] == k)
            return mid;//查找成功返回
        if(arr[mid] > k)
            high=mid-1;//继续在R[low..mid-1]中查找
        else
            low=mid+1;//继续在R[mid+1..high]中查找
    }
    if(low>high)
        return low;//当low>high时表示所查找区间内没有结果,查找失败
}

int bin_search2(int arr[],const int &n,const int &k)
{
	if(arr && n>0)// 对数组和数组长度进行了判断,非常好的改进,上面也应该由此个改进的
	{
		int low,mid,high;
		float rate;
		low = 0;
		high = n-1;
		while(low<=high)
		{
			rate = (k-arr[low])*1.0/(arr[high]-arr[low]);
			if(rate>1 || rate <0)// 对应数组的边界,不在数组中
				return -1;
			mid = low+(high-low)*rate;
			if(arr[mid] == k)
				return mid;
			else if(arr[mid] > k)
				high = mid - 1;
			else
				low = mid + 1;
		}
		return -1;// 查找失败
	}
	return -1;
}


 
 

 
 

改进的二分查找的函数:基本思想是,充分利用关键字本身的信息,用关键字和low high所对应的值的比率来确定mid,即每次排除的数据量会充分依赖关键字的大小,这比普通的二分查找效率高一些。

int bin_search2(int arr[],const int &n,const int &k)
{
	if(arr && n>0)// 对数组和数组长度进行了判断,非常好的改进,上面也应该由此个改进的
	{
		int low,mid,high;
		float rate;
		low = 0;
		high = n-1;
		while(low<=high)
		{
			rate = (k-arr[low])*1.0/(arr[high]-arr[low]);
			if(rate>1 || rate <0)// 对应数组的边界,不在数组中
				return -1;
			mid = low+(high-low)*rate;
			if(arr[mid] == k)
				return mid;
			else if(arr[mid] > k)
				high = mid - 1;
			else
				low = mid + 1;
		}
		return -1;// 查找失败
	}
	return -1;
}


1 、首先用堆进行排序,之后再二分查找

2 、有一个问题:对于一个已经排好序的数组,插入新元素的插入排序(要是再加上二分查找的思想进行插入) 和 快排和堆排 排序的效率哪一个高呢?

个人认为对于插入一个新元素(仅仅一个元素),插入排序效率搞一下(O(N)),堆排(效率是O(nlogn))和快排(nlogn不清楚)

3、既然是有序表了,为什么不用链表呢?删除的效率高,但是查找的平均效率是O(n/2),因此,对于链表来说,插入删除都是查找的时间,中和一下;貌似还是数组的有序表效率高一些。而数组的查找效率(O(logn-1)),但是插入(n/2)、删除很麻烦,总之很难说起效率……对于删除和插入频繁的还是用链表好一些。

你可能感兴趣的:(C++,二分查找,插入排序)