子数组合并

问题描述:


设子数组a[0:k-1]和a[k:n-1]已排好序(0<=k<=n-1)。试设计一个合并这两个子数组为排好序的数组a[0:n-1]的算法。要求算法在最坏情况下所用的计算时间为O(n),且只用到O(1)的辅助空间。

 

思路:

首先用二分搜索算法在数组段a[k:n-1]中搜索a[0]的插入位置,即找到位置p使得a[p]<a[0]<=a[p+1]。数组段a[0:p]向左循环移位p-k+1个位置。此时,数组元素a[p]及其左边的所用元素均已排好序。对剩余的数组元素重复上述过程,直至剩下一个数组段,此时整个数组已排好序。

例int a[7]= {7,9 ,11,13,6,8,10}

k=4,a[0]在a[k:6]的插入位置为p=4; 将数组段a[0:p]循环左移p-k+1=4-4+1=1个位置得到

a[7]={6,7,9,11,13,8,10}

此时k=p+1=5.下一个要考察的元素为a[2]

然后查看a[2]在数组a[5:n-1]的插入位置p=5 数组段a[2:5]向左循环移位p-k+1=1个位置,此时数组变为

a[7]={6,7,8,9,11,13,10}

 此时k=6,下一个要考察的元素为a[4]=11

然后查看a[4]在数组a[6:6]的插入位置为p=6,数组段a[4:6]向左循环移位6-6+1=1个位置,此时数组为

a[7]={6,7,8,9,10,11,13}

此时k=7>n-1,循环结束

 

 代码如下:

#include <iostream>
using namespace std;
int binarysearch(int a[],int x,int left,int right)//二分搜索
{
 int middle;
 while(left<=right)
 {
  middle=(left+right)/2;
 if(x==a[middle])
  return middle;
 if(x>a[middle])
  left=middle+1;
 else
  right=middle-1;
 }
 if(x>a[middle])
  return middle;
 else
  return middle-1;
}
void shiftleft(int a[],int s,int t,int k)   //a[s,t]中元素循环左移k个位置
{
 int i,j,temp;
 for(i=0;i<k;i++)
 {
  temp=a[t];
 for(j=t;j>s;j--)
  a[j]=a[j-1];
 a[s]=temp;
 }
}
void mergefor(int a[],int k,int n)
{
 int i=0,j=k;
 int p;
 while(i<j&&j<n)
 {
  p=binarysearch(a,a[i],j,n-1);
   shiftleft(a,i,p,p-j+1);
  
   i+=p-j+2;
   j=p+1;
  
 }
}
int main()
{
 int a[10]={1,5,6,7,2,3,4,8,9,10};
 int x,temp;
    int i;
 //temp=5;
   //x=binarysearch(a,temp,0,3);
 //shiftright(a,0,3,2);
 mergefor(a,4,10);
 
 for(i=0;i<10;i++)
  cout<<a[i]<<' ';
 
 //cout<<x;

 
 return 0;
}


当然,归并排序的实现步骤如下: 1. **分解(Divide)**:将待排序数组不断二分,直到每个数组只有一个元素为止。 2. **合并(Combine)**:将两个已排序的数组合并成一个更大的有序数组,这个过程重复直至整个数组排序完成。 以下是一个简单的C语言版本的归并排序函数实现: ```c #include <stdio.h> #include <stdlib.h> // 辅助函数,用于合并两个已经排好序数组 void merge(int arr[], int l, int m, int r) { int i, j, k; int n1 = m - l + 1; int n2 = r - m; // 创建临时数组 int L[n1], R[n2]; // 将左右数组复制到临时数组 for (i = 0; i < n1; i++) L[i] = arr[l + i]; for (j = 0; j < n2; j++) R[j] = arr[m + 1+ j]; // 合并临时数组回原数组 i = 0, j = 0, k = l; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } // 如果左侧剩余元素,则直接复制过来 while (i < n1) { arr[k] = L[i]; i++; k++; } // 如果右侧剩余元素,则直接复制过来 while (j < n2) { arr[k] = R[j]; j++; k++; } } // 归并排序主函数 void mergeSort(int arr[], int l, int r) { if (l < r) { // 找到中间索引 int m = l+(r-l)/2; // 分别对左半部分和右半部分进行排序 mergeSort(arr, l, m); mergeSort(arr, m+1, r); // 合并左右两部分 merge(arr, l, m, r); } } // 测试函数 int main() { int arr[] = {9, 7, 5, 11, 12, 2, 14, 3, 10, 6}; int n = sizeof(arr)/sizeof(arr[0]); printf("Original array: \n"); for(int i=0; i<n; i++) { printf("%d ", arr[i]); } mergeSort(arr, 0, n-1); printf("\nSorted array: \n"); for(int i=0; i<n; i++) { printf("%d ", arr[i]); } return 0; } ``` 当你运行这个程序时,它会对数组`arr`进行升序排序。如果需要进一步的帮助或有其他疑问,请告诉我!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值