免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5349 | 回复: 9
打印 上一主题 下一主题

子数组合并,换位问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-09-26 17:01 |只看该作者 |倒序浏览
1。
   设a[0:n-1]是一个有n个元素的数组,k(0<=k<=n-1)是一个非负整数.试设计一个算法将子数组
a[0:k]与a[k+1:n-1]换位.要求算法在最坏情况下耗时O(n), 且只用到O(1)的辅助空间.

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

请高手指点一下吧,说说思路,能有代码更好!

论坛徽章:
0
2 [报告]
发表于 2006-09-26 17:23 |只看该作者
第一个,可以 reverse 实现。先把 a[0:k] 和 a[k+1:n-1] 分别反转,再把整个 a[0:n-1] 反转。反转的算法可以是 O(n) 的时间和 O(1) 的辅助空间。

论坛徽章:
0
3 [报告]
发表于 2006-09-26 18:08 |只看该作者
谢谢

论坛徽章:
0
4 [报告]
发表于 2006-09-26 19:45 |只看该作者
第一题,不用二楼说的reverse的方法的话可以这么做:


  1. #include <stdio.h>

  2. void DisplayArray(int *pArray, int nLen)
  3. {
  4.         for (int i = 0; i < nLen; ++i)
  5.         {
  6.                 printf("array[%d] = %d\n", i, pArray[i]);
  7.         }
  8. }

  9. void SwapSubArray(int *pArray1, int *pArray2, int n)
  10. {
  11.         int temp;
  12.         for (int i = 0; i < n; ++i)
  13.         {
  14.                 temp = *(pArray1 + i);
  15.                 *(pArray1 + i) = *(pArray2 + i);
  16.                 *(pArray2 + i) = temp;
  17.         }
  18. }

  19. void ChangeArray(int *pArray, int nLen, int k)
  20. {
  21.         if (NULL == pArray)
  22.                 return;
  23.         if (k < 0 || k > nLen - 1)
  24.                 return;
  25.        
  26.         if (2 == nLen)
  27.         {
  28.                 SwapSubArray(pArray, pArray + 1, 1);
  29.                 return;
  30.         }

  31.         int m, n, num;
  32.         if (nLen - k - 1 > k + 1)                                                                // 如果后半部分的元素多
  33.         {
  34.                 m = nLen - k - 1 - k - 1;                                                        // m是两部分元素数量之差
  35.                 SwapSubArray(pArray, pArray + k + 1 + m, k + 1);        // 交换两部分元素数目相同的部分
  36.                 ChangeArray(pArray, nLen - k - 1, k);
  37.         }
  38.         else if (nLen - k - 1 < k + 1)                                                        // 如果前半部分的元素多
  39.         {
  40.                 m = k + 1 - nLen + k + 1;
  41.                 SwapSubArray(pArray, pArray + k + 1, k + 1 - m);        // 交换两部分元素数目相同的部分
  42.                 ChangeArray(pArray + nLen - k - 1, k + 1, m - 1);
  43.         }
  44.         else                                                                                                        // 前后两部分元素数量相同
  45.         {
  46.                 SwapSubArray(pArray, pArray + k + 1, k + 1);
  47.         }
  48. }

  49. int main()
  50. {
  51.         int array[] = {0, 1, 2, 3, 4, 5, 6, 7};
  52.         int nLen = sizeof(array) / sizeof(array[0]);
  53.         DisplayArray(array, nLen);

  54.         ChangeArray(array, nLen, 1);
  55.         printf("after change:\n");
  56.         DisplayArray(array, nLen);

  57.         return 1;
  58. }
复制代码


里面用到了递归,我不清楚是不是符合你的要求了.
具体的思想就是分别交换前后两部分数量相同的部分,然后再进行元素交换.

[ 本帖最后由 converse 于 2006-9-26 19:47 编辑 ]

论坛徽章:
0
5 [报告]
发表于 2006-09-26 20:07 |只看该作者
第二题很简单的了,看看代码就清楚了:



  1. #include <stdio.h>

  2. void DisplayArray(int *pArray, int nLen)
  3. {
  4.         for (int i = 0; i < nLen; ++i)
  5.         {
  6.                 printf("array[%d] = %d\n", i, pArray[i]);
  7.         }
  8. }

  9. // pArray1和pArray2是已经排好序的数组,要求将它们按照顺序合并到pArray中
  10. // 排序之后的数组不会有重复的元素
  11. void MergeArray(int *pArray1, int nLen1, int *pArray2, int nLen2, int *pArray)
  12. {
  13.         int i, j, n;

  14.         i = j = n = 0;
  15.         while (i < nLen1 && j < nLen2)                        // 循环一直进行到拷贝完某一个数组的元素为止
  16.         {
  17.                 if (pArray1[i] < pArray2[j])                // 拷贝array1的元素
  18.                 {
  19.                         pArray[n++] = pArray1[i++];
  20.                 }
  21.                 else if (pArray1[i] > pArray2[j])        // 拷贝array2的元素
  22.                 {
  23.                         pArray[n++] = pArray2[j++];                       
  24.                 }
  25.                 else                                                                // 相等的元素拷贝
  26.                 {
  27.                         pArray[n++] = pArray2[j++];                       
  28.                         ++i;
  29.                 }
  30.         }

  31.         if (i == nLen1)                                                        // 如果array1已经被拷贝完毕就拷贝array2的元素
  32.         {
  33.                 while (j < nLen2)
  34.                         pArray[n++] = pArray2[j++];
  35.         }
  36.         else                                                                        // 如果array2已经被拷贝完毕就拷贝array1的元素
  37.         {
  38.                 while (i < nLen1)
  39.                         pArray[n++] = pArray1[i++];
  40.         }
  41. }

  42. int main()
  43. {       
  44.         int array1[] = {1, 3, 5, 7};
  45.         int array2[] = {2, 4, 6, 8};
  46.         int array3[8];
  47.         MergeArray(array1, 4, array2, 4, array3);
  48.         printf("Merge Array:\n");
  49.         DisplayArray(array3, 8);

  50.         return 1;
  51. }

复制代码

论坛徽章:
0
6 [报告]
发表于 2006-09-26 21:21 |只看该作者
非常谢谢converse ,不过你好像理解错第二题的意思了,题目是不能开辟新数组空间的。
刚才在CSDN上有人告诉我说第二题是不能实现的,除非用链表,看来是这样了。

论坛徽章:
0
7 [报告]
发表于 2006-09-26 21:33 |只看该作者
原帖由 lcy3125891 于 2006-9-26 21:21 发表
非常谢谢converse ,不过你好像理解错第二题的意思了,题目是不能开辟新数组空间的。
刚才在CSDN上有人告诉我说第二题是不能实现的,除非用链表,看来是这样了。


不开辟新的,如何保证两个是连在一起的?显然只能用链表了

论坛徽章:
0
8 [报告]
发表于 2006-09-26 21:47 |只看该作者
不好意思,这是我们的<<算法设计与分析>>里的一道题目,我也是刚知道无解的.

论坛徽章:
0
9 [报告]
发表于 2006-09-27 00:42 |只看该作者
第一题
基本思路是尽量将每个元素直接移到其应该在的位置,总的操作数为数组长度N,只需要用一个临时空间。例如
0 1 2 3 4 5 6 7 8
3 4 5 6 7 8 0 1 2
操作步骤为
tmp = a[0]; a[0] = a[3]; a[3] = a[6]; a[6] = tmp;
tmp = a[1]; a[1] = a[4]; a[4] = a[7]; a[7] = tmp;
....
关键是找出 a[ i ] = a[t], 在这里记数组长度为n,第一个子数组的长度为k,容易得出
t = ( i < n - k) ? (i + k) : ( i - n + k);
还有就是注意上面这种“循环”的情况,所以在代码中有 if ( j == t) 的条件判断。

#include <stdio.h>
#define N 9

void swaparray(int *, int, int);

int main(int argc, char **argv)
{
        int i;
        int a[N];
        for (i = 0; i < N; i++)
                a[i] = i;
       
        swaparray(a, N, 6);
        for (i = 0; i < N; i++)
                printf("%2d ",a[i]);
        putchar('\n');
        return 0;
}

/*
*@n Length of a
*@k Length of first subarray
*/
void swaparray(int *a, int n, int k)
{
        int i, j, t, c, tmp;
        i = j = c = 0;
       
        if ( a == NULL || k < 1 || k >= n || n < 1)
                return;
       
        while (c < n){
                i = j;
                tmp = a[i];
                while (1) {
                        t = (i < n - k) ? (i + k) : (i - n + k);
                        if ( j == t){
                                break;
                        } else {
                                a[i] = a[t];
                                i = t;
                                c++;
                        }
                }
                a[i] = tmp;
                c++;
                j++;
        }
       
}

评分

参与人数 1可用积分 +5 收起 理由
converse + 5 我很赞同

查看全部评分

论坛徽章:
0
10 [报告]
发表于 2006-09-27 01:23 |只看该作者
carleo21 (carleo)  的算法很好,学习了~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP