【问题标题】:C++ Bubble sorting a Doubly Linked ListC++ 冒泡排序双向链表
【发布时间】:2011-04-13 13:16:06
【问题描述】:

我知道冒泡排序可能不是最快的方法,但它可以接受。我只是在将算法调整为数组中的双链接列表时遇到了麻烦。

我的双链表有一个 int 类型和一个 string 类型来保存一个数字和一个单词。我的列表是使用我编写的按字母顺序排序的插入排序进行排序的,现在我需要按数字重新排序我的双链表,从大到小。

我的麻烦点是如何运行这个循环,以便正确地彻底排序,而不仅仅是一次。

这是我到目前为止所取得的成果:

void DblLinkedList::ReorderListNumeric()
{
dummy = new Node();
temphead = head;
temp = head->next;

while(tempTwo->next != NULL)
{
    if(temp->wordCount < tempTwo->wordCount)
    {               
        dummy->word = tempTwo->word;
        dummy->wordCount = tempTwo->wordCount;

        tempTwo->word = temp->word;
        tempTwo->wordCount = temp->wordCount;

        temp->word = dummy->word;
        temp->wordCount = dummy->wordCount;
    }
    temp = tempTwo;
    tempTwo = tempTwo->next;
}
}

【问题讨论】:

  • 创建一个函数 swap(i,j) 以便您可以对其进行单元测试。
  • 只是为了涵盖我们所有的基础:我假设您已经知道现有的链表实现和 C++ STL 中的内置排序功能,并且您当前的工作是爱好或学校作业。
  • 在某些条件下,冒泡排序通常是最优的。不要因为它的渐近性能而打折扣。
  • 是的,有些地方可以接受冒泡排序。我实际上用它来对我公司记录中的交易进行排序(一个简单的 OOo 电子表格,用于处理 txn 清单、资产负债表和损益表)。由于这大部分已经排序(除了最后的 3 或 4 笔交易),它通常非常快。而且,不,我不能使用标准排序,因为事务跨越多行,排序键只在第一行,我必须把它放在一起。通过在交替方向上进行传递,添加需要向上某处的 txn 也很有用。

标签: c++ linked-list double bubble-sort


【解决方案1】:

我的麻烦点是如何运行这个循环,以便正确地彻底排序,而不仅仅是一次。

如果您已经有一个循环可以成功完成一次传递并且交换是可以的,那么相对有效地进行多次传递的通常方法是:

set swapped = true
while swapped:
    set swapped = false
    do your one pass, setting swapped to true whenever you swap

这避免了初学者总是会开始使用的幼稚 n2 解决方案。

真的就是这样。

您将swapped 设置为true,以便您最初进入列表,然后在循环内立即将其设置为false

只有在交换发生时,您的单次传递才会设置swapped。如果在您的通行证中没有发生交换,则列表已排序并退出循环。

如果发生 any 交换,则设置 swapped 标志,您将需要运行另一遍。这是因为交换可能位于列表的末尾并在更早的时候使订单无效,例如:

Initial: 1   2   3   4   6   7   5
  Pass1: 1   2   3   4   6   5<=>7 (swap)
  Pass2: 1   2   3   4   5<=>6   7 (swap)
  Pass3: 1   2   3   4   5   6   7 (no swap, so exit loop)

因此,假设您的代码是正确的,请从以下内容开始:

void DblLinkedList::ReorderListNumeric() {
    Node *ptr, *dummy = new Node();

    // Zero or one element, no sort required.

    if (head == NULL) return;
    if (head->next == NULL) return;

    // Force initial entry.

    int swapped = 1;
    while (swapped) {
        // Flag as last time, then do one pass.

        swapped = 0;

        ptr = head;
        while (ptr->next != NULL) {
            if (ptr->wordCount < ptr->next->wordCount) {
                // Swapping, need another pass.

                swapped = 1;

                dummy->word = ptr->word;
                ptr->word = ptr->next->word;
                ptr->next->word = dummy->word;

                dummy->wordCount = ptr->wordCount;
                ptr->wordCount = ptr->next->wordCount;
                ptr->next->wordCount = dummy->wordCount;
            }
            ptr = ptr->next;
        }
    }
}

【讨论】:

  • 另一个优化是利用在第一次通过后,最后一项是正确的知识 - 您不必连续通过整个列表。
  • 这不是一个坏主意。您需要计算列表的长度,但您可以在第一次通过时执行此操作,以便在后续通过时递减并使用。但是使用冒泡排序的人可能不会担心效率:-)
  • 非常感谢您抽出宝贵时间解释那里发生的事情。今天又学了一个!在摆弄我的代码 10 分钟后,效果惊人!
  • 今天又学到了新东西*!!
【解决方案2】:

使用 2 个循环对列表进行彻底排序(我不考虑这里的效率,因为这对你来说并不重要)。因此,使用 2 个指针迭代列表,就像使用数组一样 -

void DblLinkedList::ReorderListNumeric()
{
    NODE* temphead = NULL; // assuming your list is made of NODEs
    NODE* temp = NULL;

    for(temphead = head; temphead && temphead->next != NULL; ++ temphead)
    {
        for(temp = temphead->next; temp && temp->next != NULL; ++temp)
        {
            if(temphead->wordCount < temp->wordCount)
            {
                std::string dummyWord = temp->word;
                int dummyCount = temp->wordCount;

                temp->word = temphead->word;
                temp->wordCount = temphead->wordCount;

                temphead->word = dummyWord;
                temphead->wordCount = dummyCount;
            }
        }
    }
}

顺便说一句,当您只想交换值时,为什么要创建一个虚拟节点来交换。

【讨论】:

    猜你喜欢
    • 2014-02-04
    • 2022-01-09
    • 2013-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多