Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2098590
  • 博文数量: 249
  • 博客积分: 1305
  • 博客等级: 军士长
  • 技术积分: 4733
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-17 10:37
个人简介

不懂的东西还有很多,随着不断的学习,不懂的东西更多,无法消灭更多不懂的东西,那就不断的充实自己吧。 欢迎关注微信公众号:菜鸟的机器学习

文章分类

全部博文(249)

文章存档

2015年(1)

2014年(4)

2013年(208)

2012年(35)

2011年(1)

分类: C/C++

2013-04-16 15:36:37


问题描述:

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

分析与解答:

(1)向右循环换位合并

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

  1. #include <iostream>
  2. using namespace std;

  3. #define MAXNUM 100

  4. //下面函数将数组段a[s:t]中元素循环右移位k个位置
  5. void shiftright(int a[], int s, int t, int k)
  6. {
  7.     int i = 0;
  8.     int j = 0;
  9.     for(i = 0; i < k; i++)
  10.     {
  11.         int tmp = a[t];
  12.         for(j = t; j > s; j--)
  13.         {
  14.             a[j] = a[j-1];
  15.         }
  16.         a[s] = tmp;
  17.     }
  18. }

  19. //下面函数用于在数组段中a[left:right]中搜索元素x的插入位置
  20. int binarySearch(int a[], int x, int left, int right)
  21. {
  22.     int mid;
  23.     while(left <= right)
  24.     {
  25.         mid = left + (right - left)/2;
  26.         if(x == a[mid])
  27.         {
  28.             return mid;
  29.         }
  30.         if(x > a[mid])
  31.         {
  32.             left = mid + 1;
  33.         }
  34.         else
  35.         {
  36.             right = mid - 1;
  37.         }
  38.     }
  39.     if(x > a[mid])
  40.     {
  41.         return mid;
  42.     }
  43.     else
  44.     {
  45.         return mid - 1;
  46.     }
  47. }

  48. //向右循环移位合并算法
  49. //length:数组的长度
  50. void mergefor(int a[], int k, int length)
  51. {
  52.     //merge a[0:k-1] and a[k:n-1]
  53.     int i = 0;
  54.     int j = k;
  55.     while(i < j && j < length)
  56.     {
  57.         int p = binarySearch(a, a[i], j, length - 1);
  58.         shiftright(a, i, p, p - j + 1);
  59.         j = p + 1;
  60.         i += p - j + 2;
  61.     }
  62. }

  63. int main(int argc, char* argv[])
  64. {
  65.     //这里的 k = 5,即a[0:4]、a[5:8]
  66.     int a[9] = {1, 3, 5 , 7, 9, 2, 4, 6, 8};
  67.     int length = sizeof(a)/ sizeof(a[0]);

  68.     cout << "原数组为:" << endl;
  69.     for(int i = 0; i < length; i++)
  70.     {
  71.         cout << a[i] << " ";
  72.     }
  73.     
  74.     
  75.     mergefor(a, 5, length);

  76.     cout << endl << "排序后为:" << endl;
  77.     for(int i = 0; i < length; i++)
  78.     {
  79.         cout << a[i] << " ";
  80.     }
  81.     cout << endl;
  82.     return 0;
  83. }
        上述算法中,数组段a[0:k-1]中元素的移动次数不超过k次,数组段a[k:n-1]中元素最多移动一次。因此,算法的元素移动总次数为:k^2+(n-k)次。算法的比较次数不超过klog(n - k)(这个不明白)。当k <n1/2时,算法的时间复杂度为O(n);反之,则为O(n*n)。
        说实话,这个算法的过程,是比较难想的,因此,为了更加好的理解,特意举例如下。
     
        
        
        


    


        参考:《算法设计与分析实验题解



                                                            梦醒潇湘love
                                                        2013年4月16日 15:36


阅读(5613) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~