[英]Iterative QuickSort in Doubly Linked List in C
我這里有一個 function 來快速排序一個使用遞歸方法的雙向鏈表。 我想知道如何將此 function 從遞歸更改為迭代快速排序。 我一直在嘗試,但我無法理解它是如何完成的。
編輯:我修改了代碼,但無法對列表進行排序。 我只是遵循了關於如何使用數組實現快速排序的算法。 它雖然沒有錯誤。
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int val;
struct Node *next;
struct Node *prev;
};
struct Stack
{
struct Node* top;
};
typedef struct Stack *stackPtr;
struct Node *CreateNode(int data)
{
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->next = newNode->prev = NULL;
newNode->val = data;
return newNode;
}
stackPtr CreateStack()
{
stackPtr stack = (stackPtr)malloc(sizeof(struct Stack));
stack->top = NULL;
}
void Push(stackPtr stack, int data)
{
struct Node *newNode = CreateNode(data);
newNode->next = stack->top;
stack->top = newNode;
}
void Pop(stackPtr stack)
{
struct Node *temp;
temp = stack->top;
stack->top = stack->top->next;
free(temp);
}
struct Node *partition(struct Node *left, struct Node *right)
{
struct Node *pivot = right;
struct Node *i = left->prev;
struct Node *ptr;
for (ptr = left; ptr != right; ptr = ptr->next)
{
if (ptr->val <= pivot->val)
{
i = (i == NULL ? left : i->next);
int temp = i->val;
i->val = ptr->val;
ptr->val = temp;
}
}
i = (i == NULL ? left : i->next);
int temp = i->val;
i->val = pivot->val;
pivot->val = temp;
return i;
}
void QuickSort(struct Node *left, struct Node *right)
{
stackPtr auxStack = CreateStack();
Push(auxStack, left->val);
Push(auxStack, right->val);
while(auxStack->top != NULL)
{
Pop(auxStack);
}
struct Node *pivot = partition(left, right);
if((pivot->val - 1) > left->val)
{
Push(auxStack, left->val);
Push(auxStack, (pivot->val - 1));
}
if((pivot->val + 1) < right->val)
{
Push(auxStack, (pivot->val + 1));
Push(auxStack, right->val);
}
}
int main()
{
struct Node *head = malloc(sizeof(struct Node));
head->val = 2;
head->prev = NULL;
struct Node *l1 = malloc(sizeof(struct Node));
l1->val = 8;
l1->prev = head;
head->next = l1;
struct Node *l2 = malloc(sizeof(struct Node));
l2->val = 3;
l2->prev = l1;
l1->next = l2;
struct Node *l3 = malloc(sizeof(struct Node));
l3->val = 5;
l3->prev = l2;
l2->next = l3;
struct Node *l4 = malloc(sizeof(struct Node));
l4->val = 10;
l4->prev = l3;
l3->next = l4;
l4->next = NULL;
// 2<=>8<=>3<=>5<=>10=>NULL
QuickSort(head, l4);
while (head != NULL)
{
printf("%d ", head->val);
head = head->next;
}
return 0;
}
假設您有一個有效的遞歸快速排序 function:
void quicksort_rec(int *a, const int *end)
{
if (a + 1 < end) {
int *pivot = partition(a, end);
quicksort_rec(a, pivot);
quicksort_rec(pivot + 1, end);
}
}
(這是對數組的快速排序,它采用指向數組開頭和(不包括)結尾的指針形式的范圍。不要在意分區 function 的詳細信息。)
當您遞歸調用quicksort_rec
時,被調用函數的局部變量存儲在調用堆棧中:隨着遞歸深度的增加,“父”遞歸的樞軸和范圍仍然可用。
如果你想把它變成一個迭代的function,你必須手動維護一個堆棧。 (John Bollinger 在評論中比我更詳細、更好地描述了這一點。)
因此,不是調用quicksort(a, b)
,而是必須將a
和b
壓入堆棧以“保存它們以備后用”。 最后壓入堆棧的東西是最先彈出的東西,所以接下來將對右側數組進行排序。
給定存儲指向int
指針的堆棧實現,我們可以將上面的遞歸 function 轉換為迭代 function:
void quicksort_iter(int *a, int *end)
{
Stack stack = {0};
push(&stack, a);
push(&stack, end);
while (isempty(&stack)) {
end = pop(&stack);
a = pop(&stack);
if (a + 1 < end) {
int *pivot = partition(a, end);
push(&stack, a);
push(&stack, pivot);
push(&stack, pivot + 1);
push(&stack, end);
}
}
}
此代碼總是同時壓入或彈出兩個項目。 請注意,開始和結束指針必須按照它們被壓入的相反順序彈出。 您還可以創建一個 pwo 指針結構,並始終推送一個這樣的結構,這可能更干凈。 如果已知子數組少於兩個項目,您還可以通過不將子數組壓入堆棧來優化這一點。
確切的實現留給讀者,yadda,yadda,... :)
但這里是上面代碼的完整實現,可以幫助您入門。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.