鏈表的排序,好的做法是交換指針域。鏈表節點的數據域可能比較大,交換數據域可能會涉及拷貝過多的內存,影響性能。鏈表是鏈式存儲,無法隨機訪問(base_addr + offset), 所以比較適合的辦法是用比較兩兩相鄰節點的冒泡排序法。當然還有一個辦法就是,把所有的鏈表地址存到一個數組裏,排序後重新遍歷設置所有指針域,這個就多了兩次遍歷,也可以。下面是交換指針域的一個單鏈表冒泡排序的例子:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
};
struct Node *listHead = NULL;
struct Node *listTail = NULL;
/* 交換指針域,冒泡排序單鏈表 */
void sortList()
{
struct Node *cur, *prev, *tmp, *last;
cur = listHead;
prev = listHead;
last = NULL;
int i = 0, j = 0;
while (cur != last) {
i = 0;
while (cur != NULL && cur->next != last) {
if (cur->data > cur->next->data) {
/* cur, cur->next 交換位置 */
tmp = cur->next;
cur->next = cur->next->next;
tmp->next = cur;
if (i > 0)
prev->next = tmp; /* 第一次交換: prev == cur */
/* 移動 prev, cur 節點,這裏cur已經是下一個 */
prev = tmp;
/* 維護頭結點 */
if (i == 0)
listHead = prev;
} else {
/* 節點不交換位置 */
prev = cur;
cur = cur->next;
}
i++;
}
/* 維護尾節點 */
if (j++ == 0) {
listTail = cur;
listTail->next = NULL;
}
last = cur;
cur = listHead;
prev = listHead;
}
}
void initList()
{
size_t i;
struct Node *node;
int nums[] = {8, 7, 6, 5, 0, 2, 3, 9, 4, 1};
for (i = 0; i < sizeof(nums) / sizeof(int); i++) {
node = (struct Node*)malloc(sizeof(struct Node));
node->data = nums[i];
node->next = NULL;
if (listHead == NULL) {
listHead = node;
}
if (listTail == NULL) {
listTail = node;
} else {
listTail->next = node;
listTail = node;
}
}
}
void printList()
{
struct Node *node;
node = listHead;
while (node != NULL) {
printf("%d ", node->data);
node = node->next;
}
printf("\n");
}
int main()
{
initList();
printf("before: ");
printList();
sortList();
printf("after : ");
printList();
printf("head %d, tail %d\n", listHead->data, listTail->data);
return 0;
}