我正在尝试使用链接列表来快速实现快速排序,并且由于某种原因,此代码崩溃了。它似乎在崩溃之前进入分区中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);
}
答案 0 :(得分:1)
你的想法已经建立(建立两个链表)。它缺乏分离和重新附加代码。在处理链接列表时,第一个要记住的是罕见,您曾在进行重新安排时需要分配新节点。您使用您给出的节点。这就是他们的目标。您的所有算法应该只是重新安排指针。
以下就是这样做的。分配列表后,不需要新节点。除此之外的算法与您的想法相同:
代码如下。我强烈建议在调试器中浏览它:
#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;
}
输出(变化)
6(1) 7(2) 1(3) 10(4) 8(5) 10(6) 4(7) 7(8) 2(9) 9(10) 1(11) 8(12) 10(13) 8(14) 6(15) 9(16) 8(17) 2(18) 8(19) 9(20)
1(3) 1(11) 2(9) 2(18) 4(7) 6(1) 6(15) 7(2) 7(8) 8(5) 8(12) 8(14) 8(17) 8(19) 9(10) 9(16) 9(20) 10(4) 10(6) 10(13)
parens中的数字是原始列表中节点的原始顺序。请注意,我特意选择了一个小的随机池来进行选择,以便体验大量的等密钥,从而证明排序是稳定的; like-keys保留其原始列表排序。例如,原始列表中有五个8
值。排序后,他们的序列是:
8(5) 8(12) 8(14) 8(17) 8(19)
这是故意的,并且通过确保我们将项目移动到拆分列表时我们总是在结束上添加它们来实现。
无论如何,我希望它有所帮助。