//二分查找的改进,是把原来的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)、删除很麻烦,总之很难说起效率……对于删除和插入频繁的还是用链表好一些。