W. :利用合并排序和二分查找实现习题2.3-7
来源:互联网 发布:python最好的书籍推荐 编辑:程序博客网 时间:2024/06/14 04:01
//author: W.
//利用合并排序和二分查找实现习题2.3-7。
//时间复杂度:O(nlgn)
#include <stdio.h>
#include <stdlib.h>
void merge(int a[], int p, int q, int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int* L = (int*)malloc(sizeof(int) * n1);
int* R = (int*)malloc(sizeof(int) * n2);
int i;
int j;
int k;
for(i = 0; i < n1; ++i)
{
L[i] = a[p+i];
}
for(j = 0; j < n2; ++j)
{
R[j] = a[q+1+j];
}
i = 0; //循环不变式初始化:L[i]和R[i]分别是L与R中最小值,新的a中加入的元素个数为0,即加入的元素是L和R中的最小元素(还没有元素呢)
j = 0;
for(k = p; k <= r; ++k)//保持:L[i]和R[i]分别是L与R中最小值,新的a中加入的元素是L和R中的最小元素,即a中已加入元素都是小于L和R中的元素,在完成++k后,a[p]~a[k-1]为已排序
{
//使用该方式的好处是在循环不变式的主循环中会在循环结束后得到结果,即对循环不变式的终止情况判断清晰
//但这种方式会导致加入L或R剩余的元素时,每次都要多一次i == n1或 j == n2的判断
if(i == n1) //使用在主循环中处理完所有操作,注意由于n1 + n2 == r - p + 1,所以这里无需判断j < n2
{
a[k] = R[j];
++j;
continue;
}
else if(j == n2)
{
a[k] = L[i];
++i;
continue;
}
if(L[i] <= R[j])
{
a[k] = L[i];
++i;
}
else
{
a[k] = R[j];
++j;
}
}
//无论采用哪种方式,此时循环不变式到此终止,即k此时为r+1,则a[p]~a[r]已排序完毕
free(L);
free(R);
}
void merge_sort(int a[], int p, int r)
{
//分治法:
int q;
if(p < r)
{
q = (p + r) / 2; //向下取整 //分解:分解成子问题,即分解成2部分子序列
merge_sort(a, p, q); //解决:递归地解各个子问题。
merge_sort(a, q+1, r);
merge(a, p, q, r); //合并:将子问题的结果合并成,即将2部分子序列通过merge函数进行合并。
}
//当p >= r时,此时a[p] ~ a[r]至多只有一个元素,则处于已排序状态 //解决:若子问题足够小,直接求解。即这里已排序,无需做任何操作
}
//正常的二分查找
int binary_search(int a[], int begin, int end, int key)
{
int mid;
while(begin <= end)
{
mid = (begin + end) / 2;
if(a[mid] < key)
{
begin = mid + 1;
}
else if(a[mid] > key)
{
end = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
//返回值:找到了返回真,没找到返回假
//参数a和b分别返回找到的值.如果没找到则忽略该值
int find_x_from_S(int S[], int length, int x, int* a, int* b)
{
if(length < 2)
{
return 0;
}
merge_sort(S, 0, length-1);//先利用合并排序对S进行排序,时间复杂度为O(nlgn)
int i;
int search_index;
for(i = 0; i < length; ++i)//总的循环时间复杂度为O(nlgn)
{
if((search_index = binary_search(S, i+1, length-1, x-S[i])) >= 0) //在循环内部进行二分查找,范围在S[i+1]~S[length-1]中查找,查找值为x-S[i]。二分查找的时间复杂度是O(lgn)
{
*a = S[i];
*b = S[search_index]; //为了检验找到的索引正确性,否则直接返回x-*a即可。
return 1;
}
}
return 0;//排序+查找的时间为nlgn + nlgn,则时间复杂度依然是O(nlgn)
}
void test_find_x_from_S()
{
int S[] = {4, 6, 3, 10, 6, 9, 8};
int i;
for(i = 0; i < sizeof(S)/sizeof(int); ++i)
{
printf("%d ", S[i]);
}
printf("/n");
int a;
int b;
int x;
for(x = 0; x < 20; ++x)
{
if(find_x_from_S(S, sizeof(S)/sizeof(int), x, &a, &b))
{
printf("x:%d = %d + %d/n", x, a, b);
}
else
{
printf("x:%d can not find/n", x);
}
}
}
int main(int argc, char** argv)
{
test_find_x_from_S();
return 0;
}
//输出:
//4 6 3 10 6 9 8
//x:0 can not find
//x:1 can not find
//x:2 can not find
//x:3 can not find
//x:4 can not find
//x:5 can not find
//x:6 can not find
//x:7 = 3 + 4
//x:8 can not find
//x:9 = 3 + 6
//x:10 = 4 + 6
//x:11 = 3 + 8
//x:12 = 3 + 9
//x:13 = 3 + 10
//x:14 = 4 + 10
//x:15 = 6 + 9
//x:16 = 6 + 10
//x:17 = 8 + 9
//x:18 = 8 + 10
//x:19 = 9 + 10
- W. :利用合并排序和二分查找实现习题2.3-7
- W. :利用最小优先级队列实现对k个已序队列的合并排序。习题6.5-8
- 算法导论习题2.3-6 用二分查找改进插入排序(c实现)
- JAVA实现冒泡排序和二分查找
- JAVA实现冒泡排序和二分查找
- 二分查找和二分排序
- 二分排序和查找
- 排序和二分查找
- 冒泡排序和选择排序二分查找代码实现
- W. :合并排序
- 数组合并,排序,和查找
- 快速排序和二分查找算法的实现C语言
- 冒泡排序和二分查找
- 快速排序 和 二分查找
- 冒泡排序和二分查找
- 冒泡排序和二分查找
- 二分查找和快速排序
- 二分查找和排序算法
- 在VC++MFC下如何定义全局变量和全局函数
- 网络数据请求
- LINQ语句之Select/Distinct和Count/Sum/Min/Max/Avg
- Flex示例:PopUpManager在全局坐标中心弹出窗口
- DataGrid列自定义显示(模板)
- W. :利用合并排序和二分查找实现习题2.3-7
- 线程的安全退出
- DOS下常用命令大集合
- 自学网站
- 大家好
- http://www.zynews.com/news/2010-10/08/content_764609_30.htm
- 常给自己敲敲钟
- Android Animation学习笔记
- #pragma