洗牌算法2-分治

中文版本見https://github.com/lmdyyh/The-Art-Of-Programming-By-July/tree/master/ebook/zh,第35章

###Solution 2 、Perfect shuffle algorithm

Who has played poker knows,an in-shuffle of a deck of cards is done by cutting the deck into two equal halves and interleaving them perfectly, with the first card of the second half being the first card of the shuffled deck.As shown below:

If the deck is represented by a1 a2 a3 a4 b1 b2 b3 b4(To simplify,assuming the deck only has 8 cards),cut into two halves,a1 a2 a3 a4 in your left hand,b1 b2 b3 b4 in your right hand,after shuffled as in the above chart,the card may be like b1 a1 b2 a2 b3 a3 b4 a4。

Technology comes from life,2004,Peiyush Jain from microsoft has proposed perfect shuffle algorithm in his paper “A Simple In-Place Algorithm for In-Shuffle”.

How this algorithm to solve a problem? What is the link with this subject?

Yeah,as the name suggests,perfect shuffling algorithm is to solve the problem of perfect shuffle.What is the problem of the perfect shuffle?That is, given an array of a1,a2,a3,...an,b1,b2,b3..bn,It eventually replaced by b1,a1,b2,a2,...bn,an.As you can see,this issue is entirely consistent with perfect shuffle essentially.Just swap any two adjacent elements of its final sequence on the basis of perfect shuffle problem.

Namely:

a1,a2,a3,...an,b1,b2,b3..bn

By perfect shuffle problem,we get:

b1,a1,b2,a2,b3,a3... bn,an

then swap any two adjacent elements to achieve the requirements of this subject.

a1,b1,a2,b2,a3,b3....,an,bn

That is,If we apply perfect shuffle algorithm(O(N) time complexity,O(1) space complexity) solve the problem of perfect shuffle,it also solves this subject indirectly.

While there are many articles on the Internet explainint or translating this paper,but for beginners,it is too difficult to understand,furthermore,If translating the original directly,it can hardly see how the algorithm come step by step.Therefore, we begin with the basic prototype of perfect shuffling algorithm to make it better understood.

#### 2.1、Position replacement pefect_shuffle1 algorithm

To facilitate the discussion,we set the array index starting at 1,ranging from [1 .. 2n],also the above example with n=4,let us to see what the hell happens.

Start sequence:a1 a2 a3 a4 b1 b2 b3 b4

Array subscript:1 2 3 4 5 6 7 8

Final sequence:b1 a1 b2 a2 b3 a3 b4 a4

From the above examples we can see,the first n elements

>

The first element a1 to the original position of the second element a2,that is 1->2;

>

The second element a2 to the original position of the forth element a4,that is 2->4;

>

The third element a3 to the original position of the sixth element b2,that is 3->6;

>

The forth element a4 to the original position of the eighth element b4,that is 4->8;

which is extended to the general,for the elements of second half,the i-th element goes to the original position of the (2 * (i - n) ) - 1 = 2 * i - (2 * n + 1) = (2 * i) % (2 * n + 1)-th element.

Then integrated into any situation,the arbitrary i-th element,we eventually change it to the (2 * i)% (2 * n + 1)-th position.Why is it? Because:

>

when 0 <i <n,original Formula = (2i) % (2 * n + 1) = 2i;

>

when i >n,original Formula (2 * i) % (2 * n + 1) unchange.

Therefore,if we then allow another array to contain the element,we put can each element directly to the location where it should be,which brings about the easiest way pefect_shuffle1,reference code below:

```c

//Time complexity O (n), space complexity O (n) and array index starts at 1

void pefect_shuffle1(int *a, int n)

{

int n2 = n * 2, i, b[N];

for (i = 1; i <= n2; ++i)

{

b[(i * 2) % (n2 + 1)] = a[i];

}

for (i = 1; i <= n2; ++i)

{

a[i] = b[i];

}

}

```

Obviously,its time complexity is O (n), but the space complexity is O (n), which is still not in line with the expected time complexity O (n) and space complexity O (1).We continue to look for better solutions.


At the same time,I also remind readers that according to the transform of the above, we can see that there are two circles.

>

One is 1 -> 2 -> 4 -> 8 -> 7 -> 5 -> 1;

>

the other is 3 -> 6 -> 3.

2.3.1 below,"cycle_leader " algorithm will again mention these two circles.

#### 2.2、Divide and conquer algorithm perfect_shuffle2

For those who familiar with divide and conquer know that we can make it smaller by divide and conquer for a relatively large-scale problem.For this subject, assume that n is even, we try to split in half from the middle of the array (for the convenience of description, just looking at the array subscript is enough):

Original array subscript:1....2n,that is(1 .. n/2, n/2+1..n)(n+1 .. n+n/2, n+n/2+1 .. 2n)

The length is both n for the first halve(1 .. n/2, n/2+1..n)and second halve(n+1 .. n+n/2, n+n/2+1 .. 2n)

Next,we swap the later n / 2 elements (n / 2 +1 .. n) of the first half with the later n /2 elements(n+1..n+n/2,getting:

>

Newly the first n elements A:(1..n/2 n+1.. n+n/2)

>

Newly the second n elements B:(n/2+1 .. n n+n/2+1 .. 2n)

In other words,when n is even, we split the original problem into A, B two sub-problems, and then converted it into solving the n' = n / 2 problem.

But when n is odd?We can put the extra element of the first half into the end, after all the elements moving forward, the last two elements of the new series have met the requirements.Then we converted it into n-1 problem by just considering the former 2 * (n-1) elements.

For the case of n is respectively even and odd, the following gives two examples of n = 4 n = 5.

①when n=4 ,the original array is

a1 a2 a3 a4 b1 b2 b3 b4

Accordance with the idea when n is even, swap the later two elements a3 a4 of the first half with the former two elements b1 b2 of the second half, we get:

a1 a2 b1 b2 a3 a4 b3 b4

Therefore, as long as we continue with pefect_shuffle1 algorithm for solving A (a1 a2 b1 b2) and B (a3 a4 b3 b4) two sub-questions on it.

②when n=5 ,the original array is

a1 a2 a3 a4 a5 b1 b2 b3 b4 b5

In accordance with the idea above n is odd, put a5 into the end and then all the remaining elements moving forward, we get:

a1 a2 a3 a4 b1 b2 b3 b4 b5 a5

At this point, the last two elements b5 a5 already is the result we want, as long as with the previous case n = 4, the same can be considered.

reference code below:

```c

//copyright@caopengcs 8/23/2013

//Time complexity O (n), space complexity O (1) and array index starts at 1

void perfect_shuffle2(int *a, int n)

{

int t, i;

if (n == 1)

{

t = a[1];

a[1] = a[2];

a[2] = t;

return;

}

int n2 = n * 2, n3 = n / 2;

if (n % 2 == 1) //for the odd case

{

t = a[n];

for (i = n + 1; i <= n2; ++i)

{

a[i - 1] = a[i];

}

a[n2] = t;

--n;

}

//the even case below


for (i = n3 + 1; i <= n; ++i)

{

t = a[i];

a[i] = a[i + n3];

a[i + n3] = t;

}


// [1.. n /2]

perfect_shuffle2(a, n3);

perfect_shuffle2(a + n, n3);

}

```

Analysis of the complexity of this algorithm: each time we exchanged the middle of n elements, requires O (n) time, n is odd, we also need to O (n) time after the first two elements are adjusted, but this does not affect the overall time complexity.

Therefore, the fact is that when we use divide and conquer algorithm its time complexity is calculated as: T (n) = 2 * T (n / 2) + O (n), this is the same with the complexity of merge sort formula, from "Introduction to Algorithms" and can ultimately be solved for T (n) = O (nlogn). As for space, the algorithm carries out in the internal array, it is O (1) (without taking into account the premise of recursion stack space).

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章