Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/laravel/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 带链表的稳定快速排序_C++_Linked List_Quicksort - Fatal编程技术网

C++ 带链表的稳定快速排序

C++ 带链表的稳定快速排序,c++,linked-list,quicksort,C++,Linked List,Quicksort,我正在尝试使用链表实现一个稳定的快速排序,由于某些原因,这段代码正在崩溃。它似乎在崩溃之前进入分区中while循环的第二次迭代 基本上,我使用头部作为轴心点,任何小于轴心点的东西都会进入一个新的链表,任何大于轴心点的东西也会进入一个新的链表。这是递归调用的,然后在最后它们被合并 class Node { public: Node* next; int key; int key2; Node()

我正在尝试使用链表实现一个稳定的快速排序,由于某些原因,这段代码正在崩溃。它似乎在崩溃之前进入分区中while循环的第二次迭代

基本上,我使用头部作为轴心点,任何小于轴心点的东西都会进入一个新的链表,任何大于轴心点的东西也会进入一个新的链表。这是递归调用的,然后在最后它们被合并

    class Node
    {
    public:
        Node* next;
        int key;
        int key2;

        Node()
        {
            next = NULL;
        }
    };

    void fillRandom(Node*& root, int length)
    {
       if(length != 0){
            root->key = rand()%10;
            root->next = new Node;
            fillRandom(root->next, length-1);
        }
    }

    void partitionLL(Node*& lessThan, Node*& greaterThan, Node*& root)
    {
        Node* lessThanTemp = lessThan; Node* greaterThanTemp = greaterThan;
        Node* temp = root;

        while(temp->next != NULL)
        {
            if(temp->key > root->key){
                greaterThanTemp = temp;
                greaterThanTemp->next = new Node;
                greaterThanTemp = greaterThanTemp->next;
            }else{
                lessThanTemp = temp;
                lessThanTemp->next = new Node;
                lessThanTemp = lessThanTemp->next;
            }
            temp = temp->next;
        }
    }

    void quickSort(Node* root)
    {
        if(root->next != NULL){//i.e. theres only two nodes in the list
            Node* lessThan = new Node; Node* greaterThan = new Node;
            partitionLL(lessThan, greaterThan, root);
            quickSort(lessThan);
            quickSort(greaterThan);
        }else{
            return;
        }
    }

    int main()
    {
        int length = 15;
        Node* root = new Node;

        fillRandom(root, length);
        quickSort(root);
    }
你的想法成立了(建立两个链表)。这是缺乏的分离和再附着代码。处理链表时,首先要记住的是,在进行重新排列时,很少需要分配新节点。您可以使用给定的节点。这就是他们在那里的目的。您的算法所要做的只是重新排列其中的指针

以下内容正是这样做的。一旦分配了列表,就不需要新节点。除此之外,算法与您的想法相同:

  • 使用头部节点作为轴值。将其从列表中分离
  • 沿途将列表定位节点的其余部分枚举到两个列表中的一个。注意:从一个列表移动到另一个列表的代码将节点添加到各自列表的末尾
  • 完成后,您将拥有两个列表和一个孤独的pivot节点。终止两个列表并递归
  • 一旦递归返回seek到左侧列表的末尾。这是固定枢轴节点的位置,然后右侧列表将连接到该位置
代码如下。我强烈建议在调试器中遍历它:

#include <iostream>
#include <iterator>
#include <algorithm>
#include <random>

struct Node
{
    Node* next;
    int key;
    int key2;

    Node( int key, int key2 )
        : key(key), key2(key2), next()
    {}
};

Node * createList(size_t N)
{
    std::random_device rd;
    std::mt19937 rng(rd());
    std::uniform_int_distribution<> dist(1,10);

    Node *root = nullptr;
    Node **pp = &root;
    for (int i=0; i<N; ++i)
    {
        *pp = new Node(dist(rng), i+1);
        pp = &(*pp)->next;
    }
    return root;
}

void freeList(Node *& root)
{
    while (root)
    {
        Node *tmp = root;
        root = tmp->next;
        delete tmp;
    }
}

void printList(const Node* root)
{
    for (;root;root = root->next)
        std::cout << root->key << '(' << root->key2 << ") ";
    std::cout << '\n';
}

// quicksort a linked list.
void quickSort(Node *&root)
{
    // trivial lists are just returned immediately
    if  (!root || !(root->next))
        return;

    Node *lhs = nullptr, **pplhs = &lhs;
    Node *rhs = nullptr, **pprhs = &rhs;
    Node *pvt = root;
    root = root->next;
    pvt->next = nullptr;

    while (root)
    {
        if (root->key < pvt->key)
        {
            *pplhs = root; // tack on lhs list end
            pplhs = &(*pplhs)->next;
        }
        else
        {
            *pprhs = root; // tack on rhs list end
            pprhs = &(*pprhs)->next;
        }
        root = root->next;
    }

    // terminate both list. note that the pivot is still
    //  unlinked, and will remain so until we merge
    *pplhs = *pprhs = nullptr;

    // invoke on sublists.
    quickSort(lhs);
    quickSort(rhs);

    // find end of lhs list, slip the pivot into  position, then 
    //  tack on the rhs list.
    while (*pplhs)
        pplhs = &(*pplhs)->next;
    *pplhs = pvt;
    pvt->next = rhs;

    // set final output
    root = lhs;
}

int main()
{
    Node *root = createList(20);
    printList(root);
    quickSort(root);
    printList(root);
    freeList(root);
    return 0;
}
parens中的数字是原始列表中节点的原始顺序。注意,我特别选择了一个小的随机池进行选择,以体验大量相同的密钥,从而证明排序是稳定的;like键保留其原始列表顺序。例如,原始列表中有五个
8
值。排序后,它们的顺序是:

8(5) 8(12) 8(14) 8(17) 8(19)
这是有意的,并且通过确保当我们将项目移动到拆分列表时,我们总是将它们固定在末端来实现


无论如何,我希望它能有所帮助。

现在是学习如何使用调试器的最佳时机。如果生成程序的调试版本并在调试器中运行,则调试器将在崩溃处停止。然后,调试器将允许您检查和遍历函数调用堆栈(例如,如果它在库代码中停止),还允许您检查变量的值。调试器还可以用于逐行检查代码,在这种情况下可能更好,因为它将允许您确切地看到代码正在做什么,以及它为变量分配了什么值。特别是用你的
partionLL
函数,因为(对我来说)它似乎是可疑的。最后一点注意:你实际上没有对任何东西进行排序,由于
root->next
指针在您从
main
函数第一次调用
quickSort
时将为
NULL
。最后一件事让我相信您展示给我们的程序不是真正崩溃的程序,由于该程序不会执行任何可能崩溃的操作:它调用
快速排序
,然后立即返回,程序退出。这真的是崩溃程序的一部分吗?为了让事情看起来更好,我拿出了我给链表赋值的部分。我会做一个编辑把它放回去。我相信这个错误与temp->next在第一次运行后为空有关。哦,我明白了。这帮了不少忙。我现在意识到我忘了合并它们。然而,我特别问我为什么会崩溃,但事实证明,我甚至不需要这个问题的代码,只需要逻辑。不过我对你在这里做的一些事情有点困惑。为什么
ppplhs
是双指针?还有,为什么
pplhs=&lhs
。最后,如果节点不为NULL,
while(root)
是否返回true?无论如何,这确实有帮助。我也学到了一些东西。非常感谢。我使用指向指针的指针来保存将接收下一个节点指针的指针的地址。它使建立转发列表等工作变得更加容易。指向指针的指针类似于常规的单向指针,但它们所持有的是额外的间接层(它们持有指针的地址)。因此,
pplhs=&lhs
表示“将
lhs
指针的地址放入
pplhs
。关于
while(root)
C中的布尔值为零或不为零。空指针与零同义,因此
while(root)
表示“while
root
持有非空值“@amarucci13如果你发现答案有帮助,你可以用答案贴左上角的箭头勾选它。如果找到正确答案,也可以选中复选框。现在,在选择这个作为最佳答案之前,我会加快速度,看看是否有更多的答案出现,这可能更合适。是的,我试过了,但没有足够的声誉哦,在这里,你需要15票来提高投票率。@amarucci13啊,糟糕透了。好吧,希望能有帮助。花一些时间学习调试,然后在调试器中逐步完成代码(代码块或Netbeans中的gdb集成,或Windows、VS等)。听起来奇怪,调试工作代码对理解其工作方式非常有帮助。不管怎样,我很高兴这有帮助。
8(5) 8(12) 8(14) 8(17) 8(19)