有关排序的一小部分优化

「已注销」 2020-02-14 06:04:36
有两个已经排序完成的数组1 3 6 7,2 4 5 8,现在想要将其从小到大排序为一个数组

特点:两数组内存地址连续,可以看做一个数组的两段,且在栈上

目前采用以下方式连接数组,并尽可能减少内存消耗

分别从两个数组第一个元素开始,1比2小,那么从数组1拿出1放在第一个位置,此时看到数组1的第二个元素3比2大,那么接下来一个是2,看到数组2的第二个元素4,4大于3,那么下一个是3,以此类推

以下代码虽然使用的空间不多,但时间上不尽人意,尤其是为了释放空间把排序好的数组赋值给原数组太费事了,另外,该函数需要多次调用,但无法使用返回在堆上排序好的数组指针,然后在函数外部释放原空间的方法,比如return temp,free part1 and part2,主要是第一次合成时,part均在栈上

请教改进建议,最好有更高效的合成方法


void recombine(int *part1, const int *part2, int len1, int len2) {
int pos1 = 0, pos2 = 0, pos = 0;
int *temp = (int *) malloc(sizeof(int) * (len1 + len2));
while (pos < len1 + len2) {
if (*(part1 + pos1) < *(part2 + pos2)) {
*(temp + pos) = *(part1 + pos1);
pos1++;
} else {
*(temp + pos) = *(part2 + pos2);
pos2++;
}
if (pos1 == len1) {
while (pos2 < len2) {
pos++;
*(temp + pos) = *(part2 + pos2);
pos2++;
}
break;
} else if (pos2 == len2) {
while (pos1 < len1) {
pos++;
*(temp + pos) = *(part1 + pos1);
pos1++;
}
break;
}
pos++;
}
for (int i = 0; i < len1 + len2; i++) {
*(part1 + i) = *(temp + i);
}
free(temp);
}
...全文
126 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2020-02-14
  • 打赏
  • 举报
回复
引用 8 楼 寻开心的回复:
这个是二路归并,求的是速度啊
那个释放内存麻烦不到哪儿去了, 结果出来后memmove / memcpy都可以,那个速度相比于算法来说不占时间啊
搞复杂了,效率反而下来,就丧失了归并算法的本意了是不是
不想耗内存,冒个泡就好了, 执行效率和 “麻烦” 你选什么呢?
找个平衡而已,各种操作都试一下,没事干,就折腾呗
寻开心 2020-02-14
  • 打赏
  • 举报
回复
这个是二路归并,求的是速度啊
那个释放内存麻烦不到哪儿去了, 结果出来后memmove / memcpy都可以,那个速度相比于算法来说不占时间啊
搞复杂了,效率反而下来,就丧失了归并算法的本意了是不是
不想耗内存,冒个泡就好了, 执行效率和 “麻烦” 你选什么呢?
「已注销」 2020-02-14
  • 打赏
  • 举报
回复
引用 5 楼 qybao的回复:
你要是觉得移动数组可能耗时,可以改成内存拷贝试试 不用嵌套循环,两个数组一起循环也可以,也就是上面的变形 for(int i=0,j=0; i<len1+len2&&j<len2;) { if (*(part1+i) > *(part2+j)) { int t = *(part2+j); memcpy(part1+i+1, part1+i, len1-i+j); //用内存拷贝的方式往后挪数组元素 j++; } i++; }
还有这种招数明天试试
qybao 2020-02-14
  • 打赏
  • 举报
回复
上面的j++前漏了*(part1+i) = t;
qybao 2020-02-14
  • 打赏
  • 举报
回复
你要是觉得移动数组可能耗时,可以改成内存拷贝试试 不用嵌套循环,两个数组一起循环也可以,也就是上面的变形 for(int i=0,j=0; i<len1+len2&&j<len2;) { if (*(part1+i) > *(part2+j)) { int t = *(part2+j); memcpy(part1+i+1, part1+i, len1-i+j); //用内存拷贝的方式往后挪数组元素 j++; } i++; }
「已注销」 2020-02-14
  • 打赏
  • 举报
回复
引用 3 楼 qybao的回复:
因为两个都是排好序的,所以在第一个数组的基础上插入第二个数组即可 for (int i=0,j=0; i<len2; i++) //第二个数组循环 for (; j<len1+len2; j++) //第一个数组从上次找到的插入位置循环(也就是j不变) if (*(part1+j) > *(part2+i)) { //和第一个数组比较,找到插入位置 int t = *(part2+i); for (int k=len1+len2-1-i; k>j; k--) //第一个数组往后挪 *(part1+k) = *(part1+k-1); *(part1+j) = t; //插入位置变为第二个数组的元素 break;//第二个数组插入完后继续下一个元素 }
插排就是后移数组这很难受,本来想优化归并的,这一堆递归下来这么多插排不太确定和上面的比哪个效率高点,现在看起来想压缩空间有点压过头了,毕竟开一个放一个
qybao 2020-02-14
  • 打赏
  • 举报
回复
因为两个都是排好序的,所以在第一个数组的基础上插入第二个数组即可 for (int i=0,j=0; i<len2; i++) //第二个数组循环 for (; j<len1+len2; j++) //第一个数组从上次找到的插入位置循环(也就是j不变) if (*(part1+j) > *(part2+i)) { //和第一个数组比较,找到插入位置 int t = *(part2+i); for (int k=len1+len2-1-i; k>j; k--) //第一个数组往后挪 *(part1+k) = *(part1+k-1); *(part1+j) = t; //插入位置变为第二个数组的元素 break;//第二个数组插入完后继续下一个元素 }
「已注销」 2020-02-14
  • 打赏
  • 举报
回复
引用 1 楼 qybao 的回复:
既然数组内存连续,直接看作一个数组就好了。第一个数组下标越界就会到达第二个数组,所以直接用下标从第一数组的开始循环到两个数组的长度和即可。
这点我当然知道,本来就是一个数组拆分出来的 如果直接把两个数组当一个排序,那我给他拆出来干嘛呢,这就更慢了 我倒是想不依靠第三个数组,直接按那种方式排,但是暂时想到的办法很混乱,程序复杂度飙升
qybao 2020-02-14
  • 打赏
  • 举报
回复
既然数组内存连续,直接看作一个数组就好了。第一个数组下标越界就会到达第二个数组,所以直接用下标从第一数组的开始循环到两个数组的长度和即可。

69,336

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧