使用有限的操作对双端队列进行排序?

时间:2015-01-30 20:05:42

标签: algorithm sorting deque

您好我在Robert Sedgewick的Algorithms第4版中遇到了一个问题。

  

出队排序。解释你如何对一副牌进行排序,限制是唯一允许的操作是查看前两张牌的值,交换前两张牌,以及将顶牌移动到牌组的底部。

我希望有人可以解释如何做到这一点,我真的迷失了。谢谢你

3 个答案:

答案 0 :(得分:2)

不要考虑具有顶部和底部的甲板,而是想象一副牌被安排在一个环中。您可以想象在两张特定牌之间放置一个标记,然后对应于牌组的顶部。您的操作"交换前两张卡"然后将两张牌交换到标记的左侧,然后操作"将牌组的顶部移到底部"然后对应于将标记向左移动一步。

鉴于此,您可以自然地调整冒泡排序以适应此设置。永久性地将环中的一个位置标记为起点。然后,重复执行以下操作:如果标记左侧的两张卡出现故障,请更换它们。然后,将标记向左移动一步。作为规则的例外,如果标记在标记的初始位置之前一步,则不进行比较。如果你在没有交换任何东西的情况下绕过圈子,你就完成了!

在伪代码中,这看起来如下:

repeat the following until no swaps are made:
    counting from i = 1 to n - 1, inclusive:
       if the top two cards are out of order, swap them.
       move the top card of the deck to the bottom.
    then, move the top card of the deck to the bottom.

希望这有帮助!

答案 1 :(得分:1)

一个非常简单的解决方案是使用Java。只需通过比较来保持顶部元素的移动,并跟踪已排序元素的数量即可。在每次迭代中,它将根据位置给我们一个最小的元素。我们将基于n和k值执行此操作。对于n个值,我们将基于较大的元素继续移动,对于k个值,我们将仅基于较小的值继续移动,最终,解决方案将来临。你可以试试看。

private void sort(Integer[] a) {
        int n = a.length-1,k=1;
        while (n>0){
            for (int i = 0; i < n; i++) {
                if (a[1]>a[0]){
                    int temp = a[0];
                    a[0] = a[1];
                    a[1] = temp;
                }
                pushToBackAndShift(a);
            }
            for (int i = 0; i < k; i++) {
                if (a[1]<a[0]){
                    int temp = a[0];
                    a[0] = a[1];
                    a[1] = temp;
                }
                pushToBackAndShift(a);
            }
            n--;k++;
        }
        pushToBackAndShift(a);
    }

private void pushToBackAndShift(Integer[] a) {
        int temp = a[0];
        for (int i = 0; i < a.length-1; i++) {
            a[i] = a[i+1];
        }
        a[a.length-1] = temp;
    }

答案 2 :(得分:0)

我有一个对自己来说很简单的策略:

将其与冒泡排序相同:1)比较(可能交换)然后移动; 2)不要比较和移动(不要更改顺序)。并且两种动作在一轮中执行52步(甲板的长度)。

条件1:

def exchange_move(cards): 
    if cards[0] > cards[1]:
        cards[0], cards[1] = cards[1], cards[0]
        cards.append(cards.popleftL())
    else:    
        cards.append(cards.popleft())

条件2:

def move(cards): 
    cards.append(cards.popleft())

并在每一轮中采取以下两种行动:

for i in range(card_len-skip):
    exchange_move(cards)
for i in range(skip)
    move(cards)

这是Python中的完整代码:

from collections import deque
import random
from enum import Enum

class Suit(Enum):
    __order__ = "spade heart club diamond"
    spade = 1
    heart = 2
    club = 3
    diamond = 4


class Card(object):
    def __init__(self, suit, value):
        assert type(suit) == Suit
        assert value > 0 and value < 14
        self._suit = suit
        self._value = value
        self.value = self._get_value()

    def _get_value(self):
        return self._suit.value * 13 + self._value

    def __lt__(self, other):
        return self.value < other.value

    def __str__(self):
        return str((self._suit.name, self._value))

cards = deque(maxlen=52)

for s in Suit:
    for i in range(13):
        cards.append(Card(s, i+1))

random.shuffle(cards)

def is_sorted(cards):
    for i in range(len(cards)-2):
        if cards[i] > cards[i+1]:
            return False
    return True

def exchange_move(cards):
    if cards[0] > cards[1]:
        cards[0], cards[1] = cards[1], cards[0]
    cards.append(cards.popleft())

def move(cards):
    cards.append(cards.popleft())

skip = 0
while(not is_sorted(cards)):
    if skip == len(cards):
        print('something strange happened')
    for i in range(len(cards)-skip):
        exchange_move(cards)
    for i in range(skip):
        move(cards)
    skip += 1

for c in cards:
    print(c)