归并排序之数组和链表

来源:互联网 发布:自学网站美工 编辑:程序博客网 时间:2024/06/09 15:12

归并排序之数组篇

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) ;    // 返回合并后的链表}
0 0
原创粉丝点击