📜  排序链表——C语言(1)

📅  最后修改于: 2023-12-03 14:54:42.708000             🧑  作者: Mango

排序链表——C语言

排序链表是对链表进行排序的一种算法,常见的排序算法有冒泡排序、插入排序、选择排序、快速排序等。将一个无序的链表转化为有序的链表,可以方便地进行查找、插入、删除等操作。本文将介绍C语言中常见的排序链表算法,并给出相应的示例代码。

冒泡排序

冒泡排序是一种基础的排序算法,基本思想是从左往右遍历链表,将相邻的两个节点比较,如果前面的节点值大于后面的节点值,则交换这两个节点的值,直到最后一个节点为止。这样可以确保最后一个节点是最大的节点。接下来,再从左往右遍历链表,但不包括最后一个节点,重复上述过程。时间复杂度为O(n^2)。

struct ListNode* bubbleSortList(struct ListNode* head) {
    if(head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *p, *q, *end = NULL;
    while(head->next != end) {
        p = head;
        while(p->next != end) {
            q = p->next;
            if(p->val > q->val) {
                int temp = p->val;
                p->val = q->val;
                q->val = temp;
            }
            p = p->next;
        }
        end = p; // 最后一个已排序节点的指针
    }
    return head;
}
插入排序

插入排序的基本思想是将一个无序的新节点插入到已排序的链表中,使得新的链表仍然有序。如果链表为空,则将新节点作为头结点。否则,从头结点开始往后遍历,找到第一个大于等于新节点的节点,将新节点插入到该节点的前面。时间复杂度为O(n^2)。

struct ListNode* insertionSortList(struct ListNode* head) {
    if(head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *dummy = malloc(sizeof(struct ListNode));
    dummy->next = head;
    struct ListNode *cur = head->next, *prev = head;
    while(cur != NULL) {
        if(cur->val >= prev->val) {
            prev = prev->next; 
        } else {
            struct ListNode *p = dummy;
            while(p->next->val <= cur->val) {
                p = p->next; 
            }
            prev->next = cur->next;
            cur->next = p->next;
            p->next = cur;
        }
        cur = prev->next; 
    }
    return dummy->next;
}
选择排序

选择排序是通过选择最小的节点,插入到有序的节点列表中对链表进行排序的一种算法。基本思想是从头结点开始遍历链表,查找链表中最小的节点,将该节点插入到已排序节点的末尾。因此,它需要两个指针:一个用于遍历未排序的节点,另一个用于指向已排序节点的末尾。

struct ListNode* selectionSortList(struct ListNode* head) {
    if(head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *dummy = malloc(sizeof(struct ListNode));
    dummy->next = head;
    struct ListNode *tail = dummy; // 已排序节点的末尾指针
    while(tail->next != NULL) {
        struct ListNode *pre = tail, *cur = tail->next, *minp = pre, *min = cur;
        while(cur != NULL) {
            if(cur->val < min->val) {
                min = cur;
                minp = pre;
            }
            pre = cur;
            cur = cur->next;
        }
        if(tail->next == min) {
            tail = tail->next; 
        } else {
            minp->next = min->next;
            min->next = tail->next;
            tail->next = min;
            tail = tail->next;
        }
    }
    return dummy->next;
}
快速排序

快速排序是一种分治的排序算法,它利用了分治的思想,将一个大问题分解成几个小问题。基本思想是选定一个基准元素,将所有比它小的元素放在它的左边,所有比它大的元素放在它的右边,然后递归地处理左右两个子列表。时间复杂度为O(nlogn)。

struct ListNode* quickSortList(struct ListNode* head) {
    if(head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode *pivot = head, *p = head->next, *q, *left = NULL, *right = NULL;
    while(p != NULL) {
        q = p->next;
        if(p->val < pivot->val) {
            p->next = left;
            left = p;
        } else {
            p->next = right;
            right = p;
        } 
        p = q;
    }
    left = quickSortList(left);
    right = quickSortList(right);
    pivot->next = right;
    if(left == NULL) {
        return pivot;
    } else {
        struct ListNode *tail = left;
        while(tail->next != NULL) {
            tail = tail->next;
        }
        tail->next = pivot;
        return left;
    }
}
总结

以上是C语言中常见的几种排序链表算法的实现。选择合适的排序算法非常重要,通常取决于数据的大小和数据的分布情况。在实际使用中,可以根据实际情况灵活使用这些算法,以提高代码的效率和性能。