排序一副牌

时间:2016-06-27 18:48:34

标签: algorithm sorting data-structures playing-cards

给出一副N张牌。您必须使用以下允许的操作对它们进行排序:

  1. 你可以看到前2张牌。
  2. 您可以互换它们。
  3. 您可以在底部插入顶部。
  4. 有什么想法吗?

1 个答案:

答案 0 :(得分:4)

这似乎是bubblesort的一个简单例子,这是一种非常低效的排序算法,由较小的元素冒泡到顶部(假设您按升序排序)。我即将推出的改进算法与原始的bubblesort算法非常相似,所以我将首先快速解释原始算法。 Bubblesort(升序)的工作原理如下,

  1. 列表中的第一个元素已标记。
  2. 如果标记元素右侧的元素小于标记元素,则交换两个元素。
  3. 无论第二步的结果如何,标记都会移动到正确的一个位置
  4. 重复步骤2和步骤3,直到标记的元素成为列表中的最后一个元素。只是为了澄清,这意味着当步骤3导致标记最后一个元素时,迭代结束并开始新的迭代。
  5. 重复上述四个步骤,直到迭代发生,标记遍历列表中的每个元素,而不发生单个交换。这是维基百科的一个例子,https://en.wikipedia.org/wiki/Bubble_sort#Step-by-step_example

    因此,让我们修改bubblesort,以便更改一些东西以适应卡片场景。让我们不要将卡片组视为卡片组,而是将其作为列表。是的,甲板上的第一张卡片会随着我们修改后的每次迭代而不断变化,但是我们可以制作它以便卡片在移动的同时仍保持第一张牌在牌组中的位置吗?这个问题是解决问题的关键。我所说的是将卡片移动到卡片的底部不会改变卡片的初始顺序,只会交换卡片。例如,考虑这一组牌,其中最左边是最顶层,最右边是底部:

    注意:(*)表示标记的卡

    *5 3 1 2 6 
    

    在稍后将解释的算法中,将5移动到牌组的底部将使得牌组看起来像这样

    3 1 2 6 *5
    

    注意5现在是甲板的底部,但订单仍然保留。 *符号表示列表/卡片组中的第一张卡片,因此如果从左到右阅读,从5开始并循环回到3,则保留订单。

    现在对于算法,我们如何使用我刚才所说的使这个修改版本的bubblesort与原始类似?很简单,使用这种标记机制来制作它,以便我们不是真正排序一个套牌,而是一个数字列表。在开始算法之前,在卡座中标记顶部卡片。以下是bubblesort每次迭代的其余步骤:

    1. 将顶部卡与其下方的卡进行比较。如果顶部卡片较大,请与下面的卡片交换。如果标记的卡被交换,则取消标记之前标记的卡并在卡组顶部标记新卡。
    2. 将卡座的顶卡放在底部。
    3. 重复步骤1和2,直到标记的卡片重新成为卡片中的第二张卡片(顶部卡片下面的卡片)
    4. 将顶部卡片放在卡座的底部,使标记的卡片成为卡片中的顶部卡片。
    5. 对于算法的每次迭代,重复这些步骤,直到发生没有交换的迭代。以下是展示修改后的bubblesort的示例:

      注意:(*)表示标记的卡

      迭代一:

      5 3 1 2 6 //Mark the first card in the deck before starting
      *5 3 1 2 6 //Compare 5(top card) with 3(card below it)
      3 *5 1 2 6 //5 > 3 so swap
      *3 5 1 2 6 //Since the marked card (5) was swapped, 3 becomes the new marked 
                 //card to preserve original order of the deck
      5 1 2 6 *3 //Top card is placed at the bottom
      1 5 2 6 *3 //5 > 1 so swap
      5 2 6 *3 1 //Put 1 at the bottom
      2 5 6 *3 1 //5 > 2 so swap
      5 6 *3 1 2 //Put 2 at the bottom
      5 6 *3 1 2 //5 < 6 so no swap
      6 *3 1 2 5 //Put 5 at the bottom
      *3 1 2 5 6 //Marked card is second to top card, so put 6 at the bottom
                 //Marked card is now at the top, so new iteration begins
      

      在进入迭代二之前,我想指出如果你运行原始的bubblesort,一次迭代的结果序列将与我们修改算法的一次迭代得到的序列相同。

      迭代二:

      *3 1 2 5 6 //3 > 1, so swap
      *1 3 2 5 6 //Remark accordingly since the former marked card was swapped
      3 2 5 6 *1 //Place 1 at the bottom
      2 3 5 6 *1 //3 > 2, so swap
      3 5 6 *1 2 //Place 2 at the bottom
      3 5 6 *1 2 //3 < 5 so no swap
      5 6 *1 2 3 //Place 3 at the bottom
      5 6 *1 2 3 //5 < 6 so no swap
      6 *1 2 3 5 //Place 5 at the bottom.
      *1 2 3 5 6 //Since marked card is second to top card, place 6 at the bottom and end iteration
      

      迭代三:

      *1 2 3 5 6 //1 < 2 so no swap
      2 3 5 6 *1 //Place 1 at the bottom
      3 5 6 *1 2 //2 < 3 so no swap and place 2 at the bottom
      5 6 *1 2 3 //3 < 5 so no swap and place 3 at the bottom
      6 *1 2 3 5 //5 < 6 so no swap and place 5 at the bottom
      *1 2 3 5 6 //Since marked card is second to top card, place 6 at the bottom and end iteration.
      

      我们现在知道要结束算法,因为发生了整个迭代而没有发生任何交换,所以现在对卡组进行了排序。至于运行时,就交换而言,最坏情况发生在最大迭代次数发生时,即n(卡组的大小)次。并且对于每次迭代,发生最坏情况的交换次数,这也是n次。所以大O是n * n或O(n ^ 2)。