单向链表排序:快速排序和归并排序

对单向链表的排序有2种形式,只改变节点的值只改变链接

// 节点
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int v, ListNode* n = NULL) {
        val = v;
        next = n;
    }
};

本文链接:单向链表排序:快速排序和归并排序

参考资料链接:
链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)

1. 归并排序(改变链接)

归并排序是最适合单链表排序的算法,因为两个链表的归并比较简单,和数组的归并过程思路相同。
需要注意的是:如何找到链表的中点?
通过2个快慢指针,快指针每一步走2个节点,慢指针每一步走1个节点,当快指针到达链表尾部时,慢指针到达链表的中间节点。

class MergeSort {
public:
    static ListNode* ListMergeSort(ListNode* pHead) {
        if (pHead == NULL || pHead->next == NULL)
            return pHead;
        ListNode* pFast = pHead;
        ListNode* pSlow = pHead;
        // 找到位于中间的节点,快慢指针,快的到结尾,慢的到中点
        while (pFast != NULL && pFast->next == NULL) {
            pFast = pFast->next->next;
            pSlow = pSlow->next;
        }
        pFast = pSlow;
        pSlow = pSlow->next; // 分割成2段
        pFast->next = NULL;
        pHead = ListMergeSort(pHead);
        pSlow = ListMergeSort(pSlow);
        pHead = merge(pHead, pSlow);
        return pHead;
    };
private:
    static ListNode* merge(ListNode* pHead1, ListNode* pHead2) {
        if (pHead1 == NULL || pHead2 == NULL) {
            return pHead1 == NULL ? pHead2 : pHead1;
        }
        // 找出合并后的链表头
        ListNode* pHead = NULL;
        if (pHead1->val > pHead2->val) {
            pHead = pHead2;
            pHead2 = pHead2->next;
        } else {
            pHead = pHead1;
            pHead1 = pHead1->next;
        }
        // 将2个链表中值较小的节点依次链接到结果链表中
        ListNode* pHead_orgin = pHead;
        while (pHead1 != NULL && pHead2 != NULL) {
            if (pHead1->val > pHead2->val) {
                pHead->next = pHead2;
                pHead2 = pHead2->next;
            } else {
                pHead->next = pHead1;
                pHead1 = pHead1->next;
            }
            pHead = pHead->next;
        }
        if (pHead1 == NULL)
            pHead->next = pHead2;
        else
            pHead->next = pHead1;
        return pHead_orgin;
    };
};

2. 快速排序(改变链接)

只改变链接的指向。
将比基元(第一个节点)小的值,链接到一个左链表中;比基元大的值,链接到一个右链表中;
将左链表,基元,右链表链接起来。

对一段链表执行划分过程时,头节点可能发生改变以及终止节点可能是非空的,因此对一段链表的划分过程需要给出
前驱节点(指向头节点)和终止节点(标志结束)
故对传入划分函数的一次链表划分处理不包括第一个节点和最后一个节点的。(双开区间)

class QuickSort {
public:
    static ListNode* ListQuickSort(ListNode* pHead) {
        if (pHead == NULL || pHead->next == NULL)
            return pHead;
        ListNode headPrev(0, pHead); // pHead 的前驱节点
        ListQuickSort(&headPrev, pHead, NULL);
        return headPrev.next;
    }
private:
    static void ListQuickSort(ListNode* pHeadPrev, ListNode* pHead, ListNode* pTail) {
        // 处理过程不涉及 pHeadPrev 和 pTail
        if (pHead == pTail || pHead->next == pTail)
            return;
        ListNode* pMid = Partation(pHeadPrev, pHead, pTail);
        ListQuickSort(pHeadPrev, pHeadPrev->next, pMid);
        ListQuickSort(pMid, pMid->next, pTail);
    };

    static ListNode* Partation(ListNode* pHeadPrev, ListNode* pHead, ListNode* pTail) {
        int key = pHead->val; // 选第一个节点为基元
        ListNode nodeL(0), nodeR(0);
        ListNode* pLeftPrev = &nodeL; // 小于基元的链表
        ListNode* pRightPrev = &nodeR; // 大于等于基元的链表
        for (ListNode* pNode = pHead->next; pNode != pTail; pNode = pNode->next) {
            if (pNode->val < key) {
                pLeftPrev->next = pNode;
                pLeftPrev = pNode;
            } else {
                pRightPrev->next = pNode;
                pRightPrev = pNode;
            }
        }
        pRightPrev->next = pTail; // 保证子链表继续和后面的相连
        pLeftPrev->next = pHead; // 基元节点链接
        pHead->next = nodeR.next;
        pHeadPrev->next = nodeL.next; // 链表头节点
        return pHead;
    };
};

3. 快速排序(改变节点值)

由于链表只能顺序索引,故不能使用数组划分的方法。
将比基元小的节点的值,依次和基元后的节点的值交换。
如 5->3->6->4->7->2
5 为基元
3 < 5: swap(3, 3) ,(起始交换位置为基元的下一个节点,即第2个节点)
6 > 5: continue;
4 < 5: swap(6, 4) (交换位置后移,交换4和第3个节点的值)
7 > 5: continue
2 < 5: swap(4, 2) (交换位置后移,交换2和第4个节点的值)

循环结束 swap(5, 2) (交换基元值和第4个节点的值)

最后得到:2->3->4->5->6->7

class QuickSortValue {
public:
    static void QuickSort(ListNode* pHead) {
        if (pHead == NULL || pHead->next == NULL)
            return;
        QuickSort(pHead, NULL);
    }
private:
    static void QuickSort(ListNode* pHead, ListNode* pTail) {
        if (pHead == pTail || pHead->next == pTail)
            return;
        ListNode* pMid = Partation(pHead, pTail);
        QuickSort(pHead, pMid);
        QuickSort(pMid->next, pTail);
    }
    static ListNode* Partation(ListNode* pHead, ListNode* pTail) {
        if (pHead == pTail || pHead->next == pTail)
            return pHead;
        ListNode* pPivot = pHead; // 基元
        int key = pHead->val;
        for (ListNode* pNode = pHead->next; pNode != pTail; pNode = pNode->next) {
            if (pNode->val < key) {
                pPivot = pPivot->next; // 将比基元小的值,依次交换到前面
                swap(pNode, pPivot);
            }
        }
        swap(pHead, pPivot);
        return pPivot;
    }
    static void swap(ListNode* pA, ListNode* pB) {
        int temp = pA->val; pA->val = pB->val; pB->val = temp;
    }
};

4. 所有源码和测试函数

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int v, ListNode* n = NULL) {
        val = v;
        next = n;
    }
};
void PrintList(ListNode* pHead) {
    while (pHead != NULL) {
        cout << pHead->val << " ";
        pHead = pHead->next;
    }
    cout << endl;
    return;
}
class MergeSort {
public:
    static ListNode* ListMergeSort(ListNode* pHead) {
        if (pHead == NULL || pHead->next == NULL)
            return pHead;
        ListNode* pFast = pHead;
        ListNode* pSlow = pHead;
        // 找到位于中间的节点,快慢指针,快的到结尾,慢的到中点
        while (pFast != NULL && pFast->next == NULL) {
            pFast = pFast->next->next;
            pSlow = pSlow->next;
        }
        pFast = pSlow;
        pSlow = pSlow->next; // 分割成2段
        pFast->next = NULL;
        pHead = ListMergeSort(pHead);
        pSlow = ListMergeSort(pSlow);
        pHead = merge(pHead, pSlow);
        return pHead;
    };
private:
    static ListNode* merge(ListNode* pHead1, ListNode* pHead2) {
        if (pHead1 == NULL || pHead2 == NULL) {
            return pHead1 == NULL ? pHead2 : pHead1;
        }
        // 找出合并后的链表头
        ListNode* pHead = NULL;
        if (pHead1->val > pHead2->val) {
            pHead = pHead2;
            pHead2 = pHead2->next;
        } else {
            pHead = pHead1;
            pHead1 = pHead1->next;
        }
        ListNode* pHead_orgin = pHead;
        while (pHead1 != NULL && pHead2 != NULL) {
            if (pHead1->val > pHead2->val) {
                pHead->next = pHead2;
                pHead2 = pHead2->next;
            } else {
                pHead->next = pHead1;
                pHead1 = pHead1->next;
            }
            pHead = pHead->next;
        }
        if (pHead1 == NULL)
            pHead->next = pHead2;
        else
            pHead->next = pHead1;
        return pHead_orgin;
    };
};

class QuickSort {
public:
    static ListNode* ListQuickSort(ListNode* pHead) {
        if (pHead == NULL || pHead->next == NULL)
            return pHead;
        ListNode headPrev(0, pHead); // pHead 的前驱节点
        ListQuickSort(&headPrev, pHead, NULL);
        return headPrev.next;
    }
private:
    static void ListQuickSort(ListNode* pHeadPrev, ListNode* pHead, ListNode* pTail) {
        if (pHead == pTail || pHead->next == pTail)
            return;
        ListNode* pMid = Partation(pHeadPrev, pHead, pTail);
        ListQuickSort(pHeadPrev, pHeadPrev->next, pMid);
        ListQuickSort(pMid, pMid->next, pTail);
    };

    static ListNode* Partation(ListNode* pHeadPrev, ListNode* pHead, ListNode* pTail) {
        int key = pHead->val; // 选第一个节点为基元
        ListNode nodeL(0), nodeR(0);
        ListNode* pLeftPrev = &nodeL;
        ListNode* pRightPrev = &nodeR;
        for (ListNode* pNode = pHead->next; pNode != pTail; pNode = pNode->next) {
            if (pNode->val < key) {
                pLeftPrev->next = pNode;
                pLeftPrev = pNode;
            } else {
                pRightPrev->next = pNode;
                pRightPrev = pNode;
            }
        }
        pRightPrev->next = pTail; // 保证子链表继续和后面的相连
        pLeftPrev->next = pHead; // 基元节点链接
        pHead->next = nodeR.next;
        pHeadPrev->next = nodeL.next;
        return pHead;
    };
};

class QuickSortValue {
public:
    static void QuickSort(ListNode* pHead) {
        if (pHead == NULL || pHead->next == NULL)
            return;
        QuickSort(pHead, NULL);
    }
private:
    static void QuickSort(ListNode* pHead, ListNode* pTail) {
        if (pHead == pTail || pHead->next == pTail)
            return;
        ListNode* pMid = Partation(pHead, pTail);
        QuickSort(pHead, pMid);
        QuickSort(pMid->next, pTail);
    }
    static ListNode* Partation(ListNode* pHead, ListNode* pTail) {
        if (pHead == pTail || pHead->next == pTail)
            return pHead;
        ListNode* pPivot = pHead; // 基元
        int key = pHead->val;
        for (ListNode* pNode = pHead->next; pNode != pTail; pNode = pNode->next) {
            if (pNode->val < key) {
                pPivot = pPivot->next; // 将比基元小的值,依次交换到前面
                swap(pNode, pPivot);
            }
        }
        swap(pHead, pPivot);
        return pPivot;
    }
    static void swap(ListNode* pA, ListNode* pB) {
        int temp = pA->val; pA->val = pB->val; pB->val = temp;
    }
};

int main() 
{
    srand(time(0));
    const int N = 30;
    ListNode* pHead = NULL;
    for (int i = 0; i < N; i++) {
        if (pHead == NULL) {
            pHead = new ListNode(rand() % 100 + 1, NULL);
        }
        else {
            ListNode* tempNode = new ListNode(rand() % 100 + 1, pHead);
            pHead = tempNode;
        }
    }
    PrintList(pHead);
    pHead = MergeSort::ListMergeSort(pHead); // merge-sort
   // pHead = QuickSort::ListQuickSort(pHead); // quick-sort-swap-node
   //QuickSortValue::QuickSort(pHead); // quick-sort-swap-value
    PrintList(pHead);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值