如题,一个数组A,元素为a1,a2,a3...an,b1,b2,b3...bn,设计一个算法将其变为a1,b1,a2,b2,a3,b3...an,bn,要求算法的时间复杂度为O(nlogn),空间复杂度为O(1)。

采用分治思想:令p=0,q=A.length-1,重复如下步骤:

1.middle=(p+q)/2;

2.start=(middle+p)/2;

3.end=(middle+q)/2;

4.A[start]...A[middle]和A[middle+1]...A[end]互换;

5.令p=p.q=middle,回到2;

6.令p=middle+1,q=q,回到2;

真正写代码的时候遇到了不小的困难,发现上面的方法适合n为2的次幂的情况。如果n不是2的次幂,那么就不能完全照搬上面的思想,譬如:

A={a1,a2,a3,a4,a5,b1,b2,b3,b4,b5},令p=0,q=9,middle=4,start=2,如果把A[2]...A[4]与A[5]...A[7]互换,那么A将 变为

{a1.a2,b1,b2,b3,a3,a4,a5,b4,b5},如果以middle为边界分成两个数组,就是{a1,a2,b1,b2,b3},{a3,a4,a5,b4,b5},已经不满足数组A原来的结构,再用递归就一定出错。

我们知道,递归调用的时候,必须保证每次调用的参数满足同样的结构,所以上面的情况只能将A分为{a1,a2,b1,b2},{a3.a4.a5,b3,b4,b5},等于说是要将b1,b2插到a2,a3,a4的前面,当让如果直接插入的话时间复杂度会很好,所以还得采用互换的方式。代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace Chapter2._1
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             while (true)
13             {
14                 //输入数据A={a1,a2,a3...an,b1,b2,b3...bn}
15                 Console.WriteLine("请输入数组");
16                 string input = Console.ReadLine();
17                 string[] strInputs = input.Split(new char[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
18                 int[] inputs;
19                 try
20                 {
21                     inputs = new int[strInputs.Length];
22                     for (int index = 0; index != strInputs.Length; index++)
23                     {
24                         inputs[index] = int.Parse(strInputs[index]);
25                     }
26                 }
27                 //如果没有输入数据,就初始化为 A={1, 3, 5, 7, 9, 2, 4, 6, 8, 10} 
28                 catch (Exception ex)
29                 {
30                     inputs = new int[10] { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
31                 }
32                 //对数组处理
33                 ReArrange(ref inputs);
34                 //输出
35                 foreach (int i in inputs)
36                 {
37                     Console.Write(i);
38                 }
39                 Console.WriteLine();
40             }
41         }
42         static void ReArrange(ref int[] an)
43         {
44             int p = 0, q = an.Length - 1;
45             Change(ref an, p, q);
46         }
47         static void Change(ref int[] an, int p, int q)
48         {
49             if (p + 1 < q)
50             {
51                 int middle=(p+q)/2;
52                 //如果n是偶数
53                 if ((middle+1 - p) % 2 == 0)
54                 {
55                     int start = (middle + p + 1) / 2;
56                     for (int index1 = start, index2 = middle + 1; index1 < middle + 1; index1++, index2++)
57                     {
58                         int temp = an[index1];
59                         an[index1] = an[index2];
60                         an[index2] = temp;
61                     }
62                     Change(ref an, p, middle);
63                     Change(ref an, middle + 1, q);
64                 }
65                     //如果n是奇数
66                 else
67                 {
68                     int start = (middle + p + 1) / 2;
69                     int val = an[middle];
70                     for (int index1 = start, index2 = middle+1; index1 < middle+1 ; index1++, index2++)
71                     {                     
72                        if(index1<middle)
73                        {
74                         int temp = an[index1];
75                         an[index1] = an[index2];
76                         an[index2-1] = temp;
77                        }
78                        else
79                        {
80                            an[index2-1]=val;
81                        }
82                     }
83                     Change(ref an, p, middle-1);
84                     Change(ref an, middle , q);
85                 }
86 
87             }
88 
89         }
90 
91     }
92 }

其中n是奇数的情况下处理略微复杂,使用了两个变量。

处理结果

12345678910;