链表实现归并(快速、插入)排序

归并排序

思路:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。

代码编写分为以下三步:
1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);
2)写出merge函数,即如何合并链表;
3)写出mergesort函数,实现上述步骤。

struct ListNode {
   int val;
   ListNode *next;
   ListNode(int x) : val(x), next(NULL) {}
};

/*归并排序*/
ListNode* findMidddleNode(ListNode* head)//寻找链表中间节点
{
    ListNode* first = head -> next;
    ListNode* second = head;
    while(first && first -> next)
    {
        first = first -> next -> next;
        second = second -> next;
    }
    return second;
}

ListNode* mergeLists(ListNode* l1, ListNode* l2)//合并链表
{
    if(!l1) return l2;
    if(!l2) return l1;
    ListNode* pNode = new ListNode(-1);
    ListNode* head = pNode;
    while(l1 && l2)
    {
        if(l1 -> val < l2 -> val)
        {
            head -> next = l1;
            l1 = l1 -> next;
        }
        else
        {
            head -> next = l2;
            l2 = l2 -> next;
        }
        head = head -> next;
    }
    if(!l1) head -> next = l2;
    if(!l2) head -> next = l1;
    return pNode -> next;
    delete pNode;
}

ListNode* sortList(ListNode* head)//归并排序
{
    if(!head || !(head -> next))
        return head;
    ListNode* middle = findMidddleNode(head);
    ListNode* right = sortList(middle -> next);
    middle -> next = NULL;
    ListNode* left = sortList(head);
    return mergeLists(left, right);
}

快速排序

思路:
1)选取第一个节点作为枢轴,然后遍历链表;
2)如果当前元素小于枢轴的元素,则采用头插法,把该位置的节点插入到链表的首位置,如果当前元素大于枢轴元素,则当前元素向后移动一位;
3)遍历一遍链表以后,最后枢轴的位置,把链表分割为两部分,前部分元素小于枢轴元素,后半部分元素大于枢轴元素;
4)分别对前半部分元素和后半部分元素进行快速排序。

代码:

struct ListNode {
   int val;
   ListNode* next;
   ListNode(int x) : val(x), next(NULL) {}
};

/*快速排序*/
void partition(ListNode* first, ListNode* last)//对链表中的元素进行划分
{
    if (first->next == last)
        return;

    ListNode* pre = first;
    ListNode* cur = pre->next;
    ListNode* privot = cur;

    //调整链表中的元素,使小于privot值的元素在privot前边,大于privot值的元素在privot后边
    while (cur->next != NULL && cur->next != last)
    {
        //头插法使小于privot值的元素在privot前边
        if (cur->next->val < privot->val)
        {
            ListNode *tmp = pre->next;
            pre->next = cur->next;
            cur->next = cur->next->next;
            pre->next->next = tmp;
        }
        else//使大于privot值的元素在privot后边
            cur = cur->next;
    }

    //递归快排前半部分
    partition(first, privot);

    //如果有多个privot的值相同,则取最后一个pirvot
    while (privot->next != last && privot->next->val == privot->val)
        privot = privot->next;

    //递归快排后半部分
    if (privot->next != last)
        partition(privot, last);
}


ListNode* sortList(ListNode* head)//快速排序 
{
    if (head == NULL || head->next == NULL)
        return head;
    ListNode *pHead = new ListNode(-1);
    pHead->next = head;
    partition(pHead, NULL);
    return pHead->next;
}

插入排序

思路:
1)将原链表分为以newHead为头节点的已排序链表和以head为头节点的待排序链表,初始时已排序链表为空;
2)顺序遍历待排序链表中的元素,在已排序链表中找到应该插入的位置,并插入;
3)最终待排序链表为空,原链表排序完毕。

代码:

struct ListNode {
   int val;
   ListNode* next;
   ListNode(int x) : val(x), next(NULL) {}
};

/*插入排序*/
ListNode *insertionSortList(ListNode* head) {
    ListNode* newHead = new ListNode(-1);
    while(head != NULL){   
        //保存head位置
        ListNode* temp = head->next;
        ListNode* cur = newHead;
        //寻找待插入的位置
        while(cur->next != NULL && cur->next->val < head->val)
            cur = cur->next;
        //插入
        head->next = cur->next;
        cur->next = head;
        //恢复head
        head = temp;
    }
    return newHead->next;      
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值