算法学习-归并排序

时间:2022-11-13 11:21:50

今天看算法导论,学习了归并排序原理,结合网上的示例自己理解后用python和c来实现

 

一、归并排序算法原理

其原理我简要用算法导论中的伪码表示,如下:

  1. ∞作为哨兵,预示不可能还有更小的数
    MERGE(A,p,q,r)
       n1=q-p+1
       n2=r-q
       LetL[1..n1+1] and R[1..n2+1] be new arrays
       for i=1 to n1
          L[i]=A[p+i-1]
       for j=1 to n2
          R[i]=A[q+j]
       L[n1+1]=∞
       R[n2+1]=∞
       i=1
       j=1
       for k=p to r
          if L[i]<=R[j]
             A[k]=L[i]
             i=i+1
          else
             A[k]=R[j]
             j=j+1

     

二、Python实现

方法一;采取非临时数组的方式,在归并期间借助动态申请左边数据集和右边数据集对数组排序

marr=[1,4,5,7,2,5,9,3]
def mergeSort(Arr,p,r):
    if p<r:
        m=(p+r)/2
        mergeSort(Arr,p,m)
        mergeSort(Arr,m+1,r)
        merge(Arr,p,m,r)
def merge(Arr,p,q,r):
    n1,n2=q-p+1,r-q
    LArr=Arr[p:q+1]
    RArr=Arr[q+1:r+1]
    i,j=0,0
    k=p
    while i<n1 and j<n2:
        if LArr[i]<=RArr[j]:
            Arr[k]=LArr[i]
            i+=1
        else:
            Arr[k]=RArr[j]
            j+=1
        k+=1
    while i<n1:
        Arr[k]=LArr[i]
        i+=1
        k+=1
    while j<n2:
        Arr[k]=RArr[j]
        j+=1
        k+=1
mergeSort(marr,0,len(marr)-1)

方法二:借助临时数组排序

arr=[1,5,2,7,4,8,3]
def merge(arr,p,q,r,tempArr):
    i,j=p,q+1
    n1,n2=q,r
    k=p
    while i<=n1 and j<=n2:
        if arr[i]<=arr[j]:
            tempArr[k]=arr[i]
            i+=1
        else:
            tempArr[k]=arr[j]
            j+=1
        k+=1
    while i<=n1:
        tempArr[k]=arr[i]
        i+=1
        k+=1
    while j<=n2:
        tempArr[k]=arr[j]
        j+=1
        k+=1
    while p<=r:
        arr[p]=tempArr[p]
        p+=1

def mergeSort(arr,p,r,tempArr):
    if p<r:
        mid=(p+r)/2
        mergeSort(arr,p,mid,tempArr)
        mergeSort(arr,mid+1,r,tempArr)
        merge(arr,p,mid,r,tempArr)

mergeSort(arr,0,len(arr)-1,tempArr)

方法二借助了一个临时数组tempArr对归并环节的数据保存,然后将归并排序号的数据集copy到原数组arr中,这样的好处是不用在归并环节动态申请数组空间,只需要一次申请一个和arr一样的数组即可,减少了gc的开销。

 

二、C实现

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

const int NUM=10;
void mergeSort(int data[], int start, int end);
void merge(int data[], int start, int mid, int end);
void printArr(int arr[], int length);

void merge2(int data[], int start, int mid, int end, int tempData[]);
void mergeSort2(int data[], int start, int end, int tempData[]);

void main(int argc, char *argv[]){
    //第一种方式实现
    int arr[NUM];
    int i;
    srand((int)time(NULL));
    for(i=0; i<NUM; i++){
        arr[i] = (int)(30*rand()/(RAND_MAX+1.0));
    }
    printArr(arr,NUM);
    mergeSort(arr, 0, NUM-1);
    printArr(arr, NUM);

    //第二种方式实现
    int* tempArr = (int*)malloc(NUM*sizeof(int));
    srand((int)time(NULL));
    for(i=0; i<NUM; i++){
        arr[i] = (int)(30*rand()/(RAND_MAX+1.0));
    }
    printArr(arr,NUM);
    mergeSort2(arr, 0, NUM-1, tempArr);
    printArr(arr, NUM);
    free(tempArr);

}

void mergeSort(int data[], int start, int end){
    int mid;
    if(start < end){
        mid = (start+end)/2;
        mergeSort(data, start, mid);
        mergeSort(data, mid+1, end);
        merge(data, start, mid, end);
    }
}

void merge(int data[], int start, int mid, int end){
    int leftLength, rightLength;
    int *temp;
    int tempStart = start;
    int tempEnd = mid+1;
    int tempkey = 0;
    leftLength = mid - start + 1;
    rightLength = end-start;
    temp = (int *)malloc(sizeof(int) * (end-start+1));
    while(tempStart<=mid && tempEnd <= end){
        if(data[tempStart] > data[tempEnd]){
           temp[tempkey++] = data[tempEnd];
           tempEnd++;
        }else{
            temp[tempkey++] = data[tempStart];
            tempStart++;
        }
    }

    while(tempStart <= mid){
          temp[tempkey++] = data[tempStart++];
    }

    while(tempEnd <= end){
        temp[tempkey++] = data[tempEnd++];
    }
    tempkey = 0;

    while(start+tempkey<=end){
        data[start+tempkey] = temp[tempkey];
        tempkey++;
    }
    free(temp);
}

void mergeSort2(int data[], int start, int end, int tempData[]){
    if(start<end){
        int mid=(start+end)/2;
        mergeSort2(data, start, mid, tempData);
        mergeSort2(data, mid+1, end, tempData);
        merge2(data, start, mid, end, tempData);
    }
}

void merge2(int data[], int start, int mid, int end, int tempData[]){
    int i=start, k=start, j=mid+1;
    while(i<=mid && j<=end){
        if(data[i]<=data[j]){
            tempData[k++]=data[i++];
        }
        else{
            tempData[k++]=data[j++];
        }
    }
    while(i<=mid){
        tempData[k++]=data[i++];
    }
    while(j<=end){
        tempData[k++]=data[j++];
    }
    for(i=start; i<=end; i++){
        data[i]=tempData[i];
    }
}

void printArr(int arr[], int length){
    int i;
    for(i=0; i<length; i++){
        printf("%d\t", arr[i]);
    }
}