【问题标题】:Randomized QuickSort with double linked lists带有双链表的随机快速排序
【发布时间】:2020-03-30 18:07:35
【问题描述】:

我正在尝试实现随机快速排序算法来处理双链表,但我做错了。出于某种原因,randomizedQuickSortList() 自我调用了 32369 次,然后我在randomizedPartitionList() 的第一行遇到了分段错误,不管那是什么(我什至尝试写一个简单的printf())。在调试器中运行它,我注意到在某个点之后,pr(在 randomizedPartitionList() 中)的值总是分别为 1 和 2。

我确信所有其他函数都可以正常工作,并且我认为 randomizedPartitionList() 函数也可以完美运行,因为我已经尝试将它与其他算法结合使用

int randomizedPartitionList(node** head, int p, int r){
    int s = rand() % (r-p) + p;
    swapNodes(head, findNode(head, s), findNode(head, r)); //the indices of the findNode() function start from 1
    int x = (*findNode(head, r))->key; //the findNode() function returns a virable of type node**
    int i = p-1;
    int j;
    for(j=p; j<r; j++)
        if((*findNode(head, j))->key <= x){
            i++;
            swapNodes(head, findNode(head, i), findNode(head, j));
        }
    swapNodes(head, findNode(head, i+1), findNode(head, j));
    return (i+1);
}

void randomizedQuickSortList(node** head, int p, int r){
    if(p<r){
        int q = randomizedPartitionList(head, p, r);
        randomizedQuickSortList(head, p, q);
        randomizedQuickSortList(head, q, r);
    }
}

【问题讨论】:

  • minimal reproducible example 会很有用。我们无法确定其他部分是否正常工作,即使它们似乎在其他地方工作,并且有确切的输入条件来确定在它不工作的情况下发生了什么总是有用的

标签: c list sorting quicksort partitioning


【解决方案1】:

代码是 Lomuto 分区方案的变体,它应该返回一个索引到现在排序的枢轴元素,然后在递归调用中排除(否则可能发生堆栈溢出,这似乎是问题所在):

        randomizedQuickSortList(head, p, q-1);
        randomizedQuickSortList(head, q+1, r);

不包括 findnode 和 swapnodes 的代码。我假设 findnode 按索引定位节点。


代码可以在分区循环中加速,因为 i 和 j 都是按顺序递增的:

int randomizedPartitionList(node** head, int p, int r){
    int s = rand() % (r-p) + p;
    swapNodes(head, findNode(head, s), findNode(head, r)); //the indices of the findNode() function start from 1
    int x = (*findNode(head, r))->key; //the findNode() function returns a variable of type node**
    int i = p-1;
    int j;
    node* inode = *findNode(head, p);
    node* jnode = inode;
    for(j=p; j<r; j++){
        if((jnode->key <= x){
            i++;
            swapNodes(head, inode, jnode);
            inode = nextNode(inode);   // new function
        }
        jnode = nextNode(jnode);       // new function
    }
    swapNodes(head, inode, jnode);
    return (i+1);
}

【讨论】:

  • 哦,你是对的,我有点困惑,因为我已经使用数组实现了算法并且我用不同的三段论完成了它,所以我不得不尝试这些更改。也非常感谢您的建议!
  • @AntonisPetropoulos - 请注意bottom up merge sort for a linked list 会更快。更快,将列表复制到数组,对数组进行排序,创建一个新的排序链表。
  • 非常感谢!在这一点上,这就是我们在大学被要求做的事情,所以我必须这样做。事实上,过去我们必须证明归并排序比其他排序算法表现更好(在给定维度之后),然后创建一个混合算法,使用归并排序中的一些元素和插入排序中的一些元素,然后证明这个比归并排序效果更好,所以总的来说我理解这些排序算法之间的区别。再次感谢您的建议!
  • @AntonisPetropoulos - 我不知道这是否会在您的班级中被接受,但是交换节点的替代方法将为快速排序的每个实例创建 3 个列表,节点 枢轴,从当前子列表移动元素被划分为3个列表,并在两个列表上使用递归!=枢轴。