这似乎是bubblesort的一个简单例子,这是一个非常低效的排序算法,由冒泡到顶部的较小元素描述(假设您是按升序排序的)。我将要介绍的修改后的算法与原始的bubblesort算法非常相似,因此我将首先快速解释原始算法。bubbleSort(升序)的工作原理如下,
列表中的第一个元素被标记。
如果标记元素右侧的元素小于标记元素,则将交换这两个元素。
无论第二步的结果如何,标记都会向右移动一个点
重复步骤2和步骤3,直到标记的元素成为列表中的最后一个元素。为了澄清,这意味着当步骤3导致标记最后一个元素时,迭代结束,新的迭代开始。
重复以上四个步骤,直到出现一个迭代,此时标记穿过列表中的每个元素,而没有发生一次交换。以下是维基百科的一个例子,https://en.wikipedia.org/wiki/Bubble_sort#Step-by-step_example
因此,让我们修改bubblesort,使一些事情发生变化,以适应卡组场景。我们不要把一副牌看作一副牌,而要把它看作一张单子。是的,牌组中的第一张牌会随着我们修改的bubblesort的每次迭代而不断变化,但是我们能使它在保持牌组中第一张牌的位置的同时移动吗?这个问题是解决问题的关键。我要说的是,将牌移到牌组底部不会改变牌的初始顺序,只有交换才会改变。例如,考虑这副牌,最左边的是最上面的,最右边的是最下面的:
注:(*)表示标记卡
*5 3 1 2 6
在后面将要解释的算法中,将5移到甲板的底部将使甲板看起来像这样
3 1 2 6 *5
注意5现在在甲板的底部,但是顺序仍然保持。*符号表示列表/牌组中的第一张牌,因此如果从左到右读取,从5开始循环回3,则顺序保持不变。
现在说到算法,我们如何使用我刚才所说的使这个修改后的bubblesort版本与原始版本相似?简单地说,使用这个标记机制,这样我们就不会真正地对一个数据组进行排序,而是对一个数字列表进行排序。在开始算法之前,在牌组中标记最上面的牌。下面是BubbleSort每次迭代的其余步骤:
把上面的卡片和下面的卡片比较一下。如果最上面的卡比较大,那么用下面的卡交换。如果标记的卡已交换,则取消标记先前标记的卡,并在卡组顶部标记新卡。
将牌组的顶部卡片放在底部。
重复步骤1和步骤2,直到标记的卡重新成为牌组中的第二张卡(位于最上面的卡下面的卡)
把最上面的卡片放在卡片组的底部,使标记的卡片成为卡片组的最上面的卡片。
在算法的每次迭代中重复这些步骤,直到没有进行交换的迭代发生。下面是一个示例来展示修改后的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)。