归并排序与链表

目录

数组的归并排序:典型的分治思想

链表的归并排序


数组的归并排序:典型的分治思想

//归并排序
#include <iostream>
using namespace std;
const int MAX = 500;
const int SENTINEL = (1<<21);//定义无穷大的数

int L[MAX/2+2],R[MAX/2+2];//定义长度的时候记得+2

void merge(int A[],int n,int left,int mid,int right){//分
    int n1 = mid - left;//前半部分长度
    int n2 = right - mid;//后半部分长度
    for(int i=0;i<n1;i++)
        L[i] = A[left+i];//A数组的左半部分
    for(int i=0;i<n2;i++)
        R[i] = A[right+i];//A数组的右半部分
    L[n1] = R[n2] = SENTINEL;//边界设置为无穷大
    int i = 0,j = 0;
    for(int k = left;k<right;k++){
        //保证A中左半部分比右半部分小
        if(L[i]<=R[j])
            A[k] = L[i++];
        else
            A[k] = R[j++];
    }
}

void mergeSort(int A[],int n,int left,int right){//治;负责整合
    if(left+1<right){//分到只剩一个元素时
        int mid = (left+right)/2;
        mergeSort(A,n,left,mid);
        mergeSort(A,n,mid,right);
        merge(A,n,left,mid,right);
    }
}

int main(){
    
    int A[MAX];
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>A[i];
    mergeSort(A,n,0,n-1);
    for(int i=0;i<n;i++)
        cout<<A[i]<<" ";
    cout<<endl;
    return 0;
}

链表的归并排序

  • 分割 cut 环节: 找到当前链表中点,并从中点将链表断开(以便在下次递归 cut 时,链表片段拥有正确边界);
    • 我们使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点。
    • 找到中点 slow 后,执行 slow.next = None 将链表切断。
    • 递归分割时,输入当前链表左端点 head 和中心节点 slow 的下一个节点 tmp(因为链表是从 slow 切断的)。
    • cut 递归终止条件: 当head.next == None时,说明只有一个节点了,直接返回此节点。
  • 合并 merge 环节: 将两个排序链表合并,转化为一个排序链表。
    • 双指针法合并,建立辅助ListNode h 作为头部。
    • 设置两指针 left, right 分别指向两链表头部,比较两指针处节点值大小,由小到大加入合并链表头部,指针交替前进,直至添加完两个链表。
    • 返回辅助ListNode h 作为头部的下个节点 h.next。
    • 时间复杂度 O(l + r),l, r 分别代表两个链表长度。
    • 当题目输入的 head == None 时,直接返回None。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(!head||!head->next)
            return head;
        ListNode* pre = head;
        ListNode* slow,*fast;
        slow = head;
        fast = head;
        while(fast&&fast->next){//快慢指针找到中间点
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = nullptr;//从中间点断开链表
        return mergeTowList(sortList(head),sortList(slow));
    }
    ListNode* mergeTowList(ListNode* l1,ListNode* l2){
        if(!l1)
            return l2;
        if(!l2)
            return l1;
        if(l1->val<l2->val){
            l1->next = mergeTowList(l1->next,l2);
            return l1;
        }else{
            l2->next = mergeTowList(l1,l2->next);
            return l2;
        }
    }
};
发布了377 篇原创文章 · 获赞 344 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/qq_41895747/article/details/104886737
今日推荐