[关闭]
@rg070836rg 2015-11-01T22:17:02.000000Z 字数 2708 阅读 1545

算法概论作业2.3

算法概论作业


Ex.2.22

给定两个有序表,大小分别为m和n。给出一个算法,以O(logm+logn)的时间找出两个列表合并后的有序列表中的第K小元素


我们从最基础的情况开始考虑,假设一个数组为空,在另一个数组中找第K小元素,很明显,如果k不超过第二个数组的长度,那么结果就是B[bLeft+k-1]
反之同理
所以,合法性判定,和终止判定如下

  1. if (k>(aRight - aLeft + 1 + bRight - bLeft + 1))
  2. {
  3. cerr << "输入不合法" << endl;
  4. return -1;
  5. }
  6. if (aLeft > aRight){
  7. return B[bLeft+ k - 1];
  8. }
  9. if (bLeft> bRight){
  10. return A[aLeft+ k - 1];
  11. }

下面,我们回归一般情况下
我们取

  1. int aMiddle = (aLeft + aRight) / 2;
  2. int bMiddle = (bLeft + bRight) / 2;

首先比较A[aMiddle]B[bMiddle]的大小
我们不妨假设A[aMiddle]>B[bMiddle]

如果满足A[aMiddle]>B[bMiddle]

那么必定有A[aMiddle+1,...,aRight]排在所有元素的(aMiddle+bMiddle)之后
同时还有B[bLeft,...,bMiddle]排在所有元素的(aMiddle+bMiddle)之前

然后那么如果

  1. k <= (aMiddle-aLeft)+(bMiddle-bLeft)+1

我们可以把A数组右边的部分舍弃,否则
我们可以把B数组的左边部分舍弃,并在剩余部分寻找第(k-舍弃部分的个数)

反之亦然。

代码如下

  1. if (A[aMiddle] > B[bMiddle])
  2. {
  3. if (k <= (aMiddle - aLeft) + (bMiddle - bLeft) + 1)
  4. FindElement(A, B, aLeft, aMiddle - 1, bLeft, bRight, k);
  5. else
  6. FindElement(A, B, aLeft, aRight, bMiddle + 1, bRight, k - (bMiddle - bLeft) - 1);
  7. }
  8. else
  9. {
  10. if (k <= ((aMiddle - aLeft) + (bMiddle - bLeft) + 1))
  11. FindElement(A, B, aLeft, aRight, bLeft, bMiddle - 1, k);
  12. else
  13. FindElement(A, B, aMiddle + 1, aRight, bLeft, bRight, k - (aMiddle - aLeft) - 1);
  14. }

全部代码如下:

  1. #include<iostream>
  2. using namespace std;
  3. int FindElement(int A[], int B[], int aLeft, int aRight, int bLeft, int bRight, int k);
  4. int main()
  5. {
  6. int A[10] = { 1, 3, 5, 6, 7, 9, 11, 13, 15, 17 };
  7. int B[5] = { 2, 4, 8, 10, 12, };
  8. //int k;
  9. //cout << "请输入k的值:";
  10. //cin >> k;
  11. for (int k = 1; k < 10; k++)
  12. cout << endl << FindElement(A, B, 0, 9, 0, 4, k);
  13. return 0;
  14. }
  15. int FindElement(int A[], int B[], int aLeft, int aRight, int bLeft, int bRight, int k)
  16. {
  17. if (k > (aRight - aLeft + 1 + bRight - bLeft + 1))
  18. {
  19. cerr << "输入不合法" << endl;
  20. return -1;
  21. }
  22. if (aLeft > aRight){
  23. return B[bLeft + k - 1];
  24. }
  25. if (bLeft > bRight){
  26. return A[aLeft + k - 1];
  27. }
  28. int aMiddle = (aLeft + aRight) / 2;
  29. int bMiddle = (bLeft + bRight) / 2;
  30. if (A[aMiddle] > B[bMiddle])
  31. {
  32. if (k <= (aMiddle - aLeft) + (bMiddle - bLeft) + 1)
  33. FindElement(A, B, aLeft, aMiddle - 1, bLeft, bRight, k);
  34. else
  35. FindElement(A, B, aLeft, aRight, bMiddle + 1, bRight, k - (bMiddle - bLeft + 1));
  36. }
  37. else
  38. {
  39. if (k <= ((aMiddle - aLeft) + (bMiddle - bLeft) + 1))
  40. FindElement(A, B, aLeft, aRight, bLeft, bMiddle - 1, k);
  41. else
  42. FindElement(A, B, aMiddle + 1, aRight, bLeft, bRight, k - (aMiddle - aLeft + 1));
  43. }
  44. }

Ex2.27

(a)

[adbe]2=[a2+bcc(a+d)b(a+d)bc+d2](1)

b)
因为分治之后得到的子问题不再是平方操作了,所以该算法的运行时间不是O(nlog25)

Ex2.31

算法:
gcd=2gcd(a/2,b/2), 若a,b都是偶数
gcd(a,b/2), 若a是奇数,b是偶数
gcd(|ab|,Min(a,b)),若a,b都是奇数

  1. int gcd(int a, int b)
  2. {
  3. if(a == 0) return b;
  4. if(b == 0) return a;
  5. if(a % 2 == 0 && b % 2 == 0) return 2 * gcd(a/2, b/2);
  6. else if(a % 2 == 0) return gcd(a/2 , b);
  7. else if(b % 2 == 0) return gcd(a, b/2);
  8. else return gcd(abs(a - b), Min(a, b));
  9. }
  10. int Min(int a,int b)
  11. {
  12. if (a >= b)
  13. {
  14. return b;
  15. }
  16. else
  17. return a;
  18. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注