数组和链表的归并排序算法实现(C语言)

来源:互联网 发布:乌鲁木齐打车软件 编辑:程序博客网 时间:2024/06/12 13:51

归并排序

二路归并

描述

时间复杂度是O(NlogN),空间复制度为O(N)(归并排序的最大缺陷)
归并排序(Merge Sort)完全遵循上述分治法三个步骤:
1、分解:将要排序的n个元素的序列分解成两个具有n/2个元素的子序列;
2、解决:使用归并排序分别递归地排序两个子序列;
3、合并:合并两个已排序的子序列,产生原问题的解。

数组代码实现

#include "stdio.h"#include "stdlib.h"#include "assert.h"#include "string.h"void print_arr(int *arr, int len){    int i = 0;    for(i = 0; i < len; i ++)        printf("%d ",arr[i]);    printf("\n");}void merge(int *arr, int low, int mid, int hight, int *tmp){    assert(arr && low >= 0 && low <= mid && mid <= hight);    int i = low;    int j = mid + 1;    int index = 0;    while(i <= mid && j <= hight)    {        if(arr[i] <= arr[j])            tmp[index++] = arr[i++];        else            tmp[index++] = arr[j++];    }    while(i <= mid) //拷贝剩下的左半部分        tmp[index++] = arr[i++];    while(j <= hight) //拷贝剩下的右半部分        tmp[index++] = arr[j++];    memcpy((void *)(arr + low), (void *)tmp, (hight - low + 1) * sizeof(int));}void mergesort(int *arr, int low, int hight, int *tmp){    assert(arr && low >= 0);    int mid;    if(low < hight)    {        mid = (hight + low) >> 1;        mergesort(arr, low, mid,tmp);        mergesort(arr, mid + 1, hight,tmp);        merge(arr, low, mid, hight,tmp);    }}//只分配一次内存,避免内存操作开销void mergesort_drive(int *arr, int len){    int *tmp = (int *)malloc(len * sizeof(int));    if(!tmp)    {        printf("out of memory\n");        exit(0);    }    mergesort(arr, 0, len - 1, tmp);    free(tmp);}int main(){    int data[10]={8,7,2,6,9,10,3,4,5,1};    int len = sizeof(data)/sizeof(data[0]);    mergesort_drive(data, len);    print_arr(data,len);    return 0;}

链表代码实现

/*当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事情。*/#include <stdio.h>#include <stdlib.h>#include <time.h>typedef int Item;typedef struct Node{    Item data;    struct Node *next;}Node,*ptrNode;ptrNode CreatListHead(int len);ptrNode CreatListTail(int len);void print_List(ptrNode List);void Mergesort_List(ptrNode *List);void Split_List(ptrNode List, ptrNode *List_A, ptrNode *List_B);ptrNode Merge_List(ptrNode List_A, ptrNode List_B);ptrNode CreatListHead(int len){    int i;    ptrNode p;    ptrNode List = (ptrNode)malloc(sizeof(struct Node));    List->next   = NULL;    for(i = 0; i < len; i ++)    {        p = (ptrNode)malloc(sizeof(struct Node));        p->data = i + 1;        p->next = List->next;        List->next = p;    }    return List;}ptrNode CreatListTail(int len){    int i;    ptrNode p;    srand(time(0));    ptrNode List = (ptrNode)malloc(sizeof(struct Node));    ptrNode Tail = List;    for(i = 0; i < len; i ++)    {        p = (ptrNode)malloc(sizeof(struct Node));        p->data = rand() % len + 1;        Tail->next = p;        Tail  = p;    }    Tail->next = NULL;    return List;}void print_List(ptrNode List){    while(List != NULL)    {        printf("%d ",List->data);        List = List->next;    }    printf("\n");}void Mergesort_List(ptrNode *List){    ptrNode Head = *List;    ptrNode List_A;    ptrNode List_B;    if(Head == NULL || Head->next == NULL)        return;    Split_List(Head, &List_A, &List_B);    Mergesort_List(&List_A);    Mergesort_List(&List_B);    *List = Merge_List(List_A,List_B);}void Split_List(ptrNode List, ptrNode *List_A, ptrNode *List_B){    ptrNode fast_list;    ptrNode low_list;    if(List == NULL || List->next == NULL)    {        *List_A = List;        *List_B = NULL;    }    else    {        low_list  = List;        fast_list = List->next;        while(fast_list != NULL)        {            fast_list = fast_list->next;            if(fast_list != NULL)            {                low_list  = low_list->next;                fast_list = fast_list->next;            }        }        *List_A = List;        *List_B = low_list->next;        low_list->next = NULL;    }}ptrNode Merge_List(ptrNode List_A, ptrNode List_B){    ptrNode List_Result = NULL;    if(List_A == NULL)        return List_B;    if(List_B == NULL)        return List_A;    if(List_A->data <= List_B->data)    {        List_Result = List_A;        List_A = List_A->next;    }    else    {        List_Result = List_B;        List_B = List_B->next;    }    List_Result->next = Merge_List(List_A,List_B);    return List_Result;}int main(){    ptrNode Head;    ptrNode List;    Head = CreatListTail(10);    List = Head -> next;    print_List(List);    Mergesort_List(&List);    print_List(List);    return 0;}

适用场景

归并排序在数据量比较大的时候也有较为出色的表现(效率上),但是,其空间复杂度O(n)使得在数据量特别大的时候(例如,1千万数据)几乎不可接受。而且,考虑到有的机器内存本身就比较小,因此,采用归并排序一定要注意。

还有其他两种归并排序的优化算法(插入归并,原地归并)参考此博文http://www.ahathinking.com/archives/103.html

0 0
原创粉丝点击