链表排序的快排实现

题目

LeetCode 148. 排序链表

快排思路

在一般情况下,我们使用数组实现的快速排序,总是选取首元节点作枢纽(privot),并通过与枢纽的值进行比较,使用“填坑-挖坑法”将枢纽放到合适的位置上。

但是链表无法这么做,链表不支持随机访问。
但是,我们只要能实现前面的值都比枢纽小,后面的值都比枢纽大,就算是找到适合的位置了。由于链表十分适合任意位置的插入删除。

因而可以考虑以下思路:
我们取出链表的首元节点作为枢纽,顺序遍历链表,使得小于首元节点的值归类与一个链表。相应的,使得大于首元节点的值归类于另一个链表。
将链表分裂成大小链表两块,最后再合并起来。

此处使用快排实现只是锻炼思路,面对题目中极端的测试用例,快排将会退化到O( n 2 n^2 n2)

快排的稳定化基本上也是基于上述的思路,快排实现的稳定与否取决于partition部分的元素排位是根据交换还是插入

/*删除next元素,并返回*/
ListNode* delNext(ListNode* lst) {
    if (lst == nullptr || lst->next == nullptr) return nullptr;

    ListNode* res = lst->next;
    lst->next = lst->next->next;
    
    return res;
}

/*添加到表尾*/
void appendTail(ListNode* head, ListNode** rear, ListNode* n) {
    if (*rear == nullptr) {
        *rear = head->next = n;
    }else {
        (*rear)->next = n;
        (*rear) = (*rear)->next;
    }
}

bool isEmpty(ListNode* head) {
    return head->next == nullptr;
}

ListNode* quickSort(ListNode* head, ListNode* tail) {
    // 空链表或者只有一个节点
    if (head == tail || head->next == tail) return head;

    ListNode  low(-1, nullptr);     // low lst 临时保存小于privot的节点
    ListNode* p_low = &low;        // low lst 头节点
    ListNode* p_low_tail = nullptr;// low lst 尾指针

    ListNode  up(-1, nullptr);
    ListNode* p_up = &up;           // max lst
    ListNode* p_up_tail = nullptr; // max lst tail

    ListNode* privot = delNext(head);
    
    ListNode* prev = head; 
    while (prev->next != tail) {
        ListNode* del = delNext(prev);
        if (del->val < privot->val)
            appendTail(p_low, &p_low_tail, del);
        else 
            appendTail(p_up, &p_up_tail, del);
        
    }

    
    if (isEmpty(p_low)) {
        head->next = privot;
    }
    else{
        head->next = p_low->next;
        p_low_tail->next = privot;
    }

    if (isEmpty(p_up)) {
        privot->next = tail;
    }
    else {
        privot->next = p_up->next;
        p_up_tail->next = tail;
    }
    

    quickSort(head, privot);
    quickSort(privot, tail);

    return head->next;
}

/* 此处head形参不包含头节点 */
ListNode* sortList(ListNode* head) {
    if (!head) return head;
    ListNode newHead(-1, head);
    return quickSort(&newHead, nullptr);
}

归并排序

ListNode* getMidNode(ListNode* head, ListNode* tail) {
    ListNode* s = head;
    ListNode* f = head->next == tail ? tail : head->next->next;

    while (f != tail) {
        s = s->next;
        f = f->next == tail ? tail : f->next->next;
    }

    return s->next;
}


void append(ListNode** head, ListNode** rear, ListNode* n) {
    if (*head == nullptr) {
        *head = n;
        *rear = n;
        return;
    }
    
    (*rear)->next = n;
    (*rear) = (*rear)->next;
}

ListNode* merge(ListNode* lst1, ListNode* lst2) {

    if (!lst1 && !lst2) return nullptr;
    ListNode* head = nullptr;
    ListNode* tail = nullptr;

    while (lst1 && lst2) {
        if (lst1->val < lst2->val) {
            append(&head, &tail, lst1);
            lst1 = lst1->next;
        }
        else {
            append(&head, &tail, lst2);
            lst2 = lst2->next;
        }
    }

    if (lst1) {
        append(&head, &tail, lst1);
    }

    if (lst2) {
        append(&head, &tail, lst2);
    }

    return head;
}

/* 此处head 无头节点 */
ListNode* mergeSort(ListNode* head, ListNode* tail) {
    if (head == nullptr) return head;
    /*防止出现链表尾节点非null*/
    if (head == tail || head->next == tail) {
        head->next = nullptr;
        return head;
    }

    ListNode* mid = getMidNode(head, tail);
    ListNode* l = mergeSort(head, mid);
    ListNode* r = mergeSort(mid, tail);
    return merge(l, r);
}

ListNode* sortList(ListNode* head) {
    if (!head) return head;
    return mergeSort(head, nullptr);
}

第二个版本:

class Solution {
public:
    std::pair<ListNode*, ListNode*>
        spliceList(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head->next ? head->next->next : nullptr;

        while (fast != nullptr) {
            slow = slow->next;
            fast = fast->next ? fast->next->next : nullptr;
        }

        ListNode* lst1 = head;
        ListNode* lst2 = slow->next;
        slow->next = nullptr;

        return { lst1, lst2 };

    }

    void append(ListNode*& list, ListNode*& rear, ListNode* n) {
        if (list == nullptr) {
            list = n;
            rear = n;
        }
        else {
            rear->next = n;
            rear = n;
        }
    }

    ListNode* merage(ListNode* lst1, ListNode* lst2) {
        ListNode* head = nullptr, * rear = nullptr;
        while (lst1 && lst2) {
            if (lst1->val < lst2->val) {
                append(head, rear, lst1);
                lst1 = lst1->next;
            }
            else {
                append(head, rear, lst2);
                lst2 = lst2->next;
            }
        }

        if (lst1) append(head, rear, lst1);
        if (lst2) append(head, rear, lst2);

        return head;
    }

    
    ListNode* mergeSort(ListNode* head) {
        if (head == nullptr || head->next == nullptr) return head;

        auto lsts = spliceList(head);

        ListNode* l = mergeSort(lsts.first);
        ListNode* r = mergeSort(lsts.second);

        return merage(l, r);
    }

    ListNode* sortList(ListNode* head) {
        if (!head) return head;
        return mergeSort(head);
    }

};
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值