归并排序之数组和链表

归并排序之数组篇

Step1: 合并两个有序的数组

void mergearray (int arr[] , int first , int mid , int last , int temp[]) {
    // temp数组是临时用来储存已经排好序的数组
    int i = first , j = mid + 1 ; 
    // i , j分别储存两个数组两部分的开头
    int m = mid , n = last ; 
    // m储存中间值,i部分的末尾;n储存末尾值,j部分的末尾
    int k = 0 ; 
    // 储存temp数组的的位置 

    while (i <= m && j <= n) { // 两部分数组都未遍历完的时候
        if (arr[i] <= arr[j])
            temp[k ++] = arr[i ++] ;
        else if (arr[i] > arr[j])
            temp[k ++] = arr[j ++] ; 
    } 
    // i , j两部分数组至少有一个已经遍历完,如果遍历完,就不会进入while循环 
    while (i <= m) // 如果i部分数组还未遍历完
        temp[k ++] = arr[i ++] ;
    while (j <= n) // 如果j部分数组还未遍历完
        temp[k ++] = arr[j ++] ;

    for (int i = 0 ; i < k ; i ++)  
        arr[first + i] = temp[i] ; 
    // 将排好序的数组复制回原数组,因为temp数组是临时的
}

Step2: 将数组一分为二,不断递归

void mergesort (int arr[] , int first , int last , int temp[]) {
    if (first == last) return ; 
    // 只有一个元素的时候,就是已经排好序的,直接返回
    if (first < last) {
        int mid = (first + last) / 2 ;
        // 找到中间点
        mergesort (arr , first , mid , temp) ; 
        // 对左边排好序 
        mergesort (arr , mid + 1 , last , temp) ; 
        // 对右边排好序 
        mergearray (arr , first , mid , last , temp) ; 
        // 将左边,右边合并进入一个数组
    } 
}

Step3: 实现更加人性化的接口(更方便客户使用)

bool mergeSort (int arr[] , int length) {
    int* p = new int [length] ; 
    // 用作临时储存数组
    if (p == NULL || length == 0) {
        return false ;
    }
    mergesort (arr , 0 , length - 1 , p) ;
    delete [] p ;
    return true ;
}

归并排序之链表篇

有这样一个链表

 struct node {
  int data;
  struct node* next;
  node(int data = 0, struct node* next = NULL) : data(data), next(next) {}
} ;

Step1: 将两个有序链表合并成一个链表

node* mergeSortedList (node* h1 , node* h2) {
    // 注意这里要返回链表指针作为参数,否则其他函数无法获得已经排好序的链表
    node* newhead ;
    if (h1 == NULL) return h2 ;
    if (h2 == NULL) return h1 ;
    // 如果有一个链表为空,那么直接返回另外一个链表指针作为头即可
    if (h1 -> data <= h2 -> data) {
        newhead = h1 ;
        h1 = h1 -> next ;
    }
    else {
        newhead = h2 ;
        h2 = h2 -> next ;
    }
    // 找到新的头指针,并且把那个向后移一个
    node* temp = newhead ;
    // 防止newhead被修改
    while (h1 && h2) {
        if (h1 -> data <= h2 -> data) {
            temp -> next = h1 ;
            temp = temp -> next ;
            h1 = h1 -> next ;
        }
        else {
            temp -> next = h2 ;
            temp = temp -> next ;
            h2 = h2 -> next ;
        }
    }
    // 如果h1没排完:
    while (h1) {
        temp -> next = h1 ;
        h1 = h1 -> next ;
        temp = temp -> next ;
    }
    // 如果h2没排完:
    while (h2) {
        temp -> next = h2 ;
        temp = temp -> next ;
        h2 = h2 -> next ;
    }
    return newhead ;
}

Step2: 将链表一分为二(注意怎么找到链表的中间点)

node* mergeSort (node* head) {
    // 注意这里需要有返回值,原因是要在递归过程把结果传递下去
    if (head == NULL || head -> next == NULL) return head ;
    // 如果是空,直接返回head
    node* fast = head , *slow = head ;
    while (fast -> next && fast -> next -> next) {
        fast = fast -> next -> next ;
        slow = slow -> next ;
    }
    // 利用fast的检索速度是slow的两倍来找到中间点
    node* leftHead = head ;
    node* rightHead = slow -> next ;
    slow -> next = NULL ; 
    // 十分十分重要的是,要把左边的尾巴断掉,即置空
    leftHead = mergeSort (leftHead) ;
    // 排好左边链表
    rightHead =  mergeSort (rightHead) ;
    // 排好右边链表
    return mergeSortedList (leftHead , rightHead) ;
    // 返回合并后的链表
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值