高效合并两个有序数组
2、没有中间变量temp,要求空间复杂度为O(1),通过交换+移位实现//将有二个有序数列a[first...mid]和a[mid...last]合并。
void mergearray(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i <= m && j <= n)
{
if (a[i] <= a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while (i <= m)
temp[k++] = a[i++];
while (j <= n)
temp[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = temp[i];
}
3、优化第二种方法,交换+循环移位(不用中间变量,通过交换反转实现),第二种方法中,每次移动的单位是一个数,效率低,可以采用块循环移动(单位是连续几个数)进行优化void swap(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void func(int a[], int n)
{
int i,j;
if (n<=0)
{
return;
}
i = 0;
j = n/2;
while(j<n && i<j)
{
if (a[i]<=a[j])
{
i++;
}
else
{
swap(a[i], a[j]);
for (int k=j-1;k>i; k--) // 每次发现一个a[i]>a[j]交换后,需要把i+1到j的子数组循环右移一
{ // 位,(i+1)~(j)保持有序,这里可以优化
swap(a[k], a[k+1]);
}
i++;
j++;
}
}
}
void Reverse(int *a , int begin , int end ) //反转
{
for(; begin < end; begin++ , end--)
swap(a[begin] , a[end]);
}
void RotateRight(int *a , int begin , int end , int k) //循环右移,a[begin:end]段向右循环移位k位
{
int len = end - begin + 1; //数组的长度
k %= len;
Reverse(a , begin , end - k);
Reverse(a , end - k + 1 , end);
Reverse(a , begin , end);
}
// 将有序数组a[begin...mid] 和 a[mid+1...end] 进行合并
void Merge(int *a , int begin , int end )
{
int i , j , k;
i = begin;
j = 1 + ((begin + end)>>1); //位运算的优先级比较低,需要加一个括号
while(i <= end && j <= end && i<j)
{
while(i <= end && a[i] < a[j])
i++;
k = j; //暂时保存指针j的位置
while(j <= end && a[j] < a[i]) // 找到连续的j索引列都小于a[i],进行块循环移动
j++;
if(j > k)
RotateRight(a , i , j-1 , j-k); //数组a[i...j-1]循环右移j-k次,a[i..j-1]始终有序
i += (j-k+1); //第一个指针往后移动,因为循环右移后,数组a[i....i+j-k]是有序的
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)