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

原创 2015年03月05日 21:11:25

归并排序

二路归并

描述

时间复杂度是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

版权声明:本文为博主原创文章,未经博主允许不得转载。

对数组进行归并排序

代码如下: 下列的代码有几处trick。第一:在整个算法流程中,我们只分配了一次动态数组。第二,tmpArray在这里起到的作用是临时存储merge的结果,merge之后,需要把tmpArray里面...
  • wusecaiyun
  • wusecaiyun
  • 2015年09月21日 16:36
  • 605

归并排序C++实现——基于数组的

归并排序C++实现——基于数组的 /关于归并排序理论知识网上应该也很详细了,我在这里就分享一下自己的代码实现,有错误的地方欢迎大家指出/#include //能不用using namespace...
  • ke1950523491
  • ke1950523491
  • 2017年11月30日 10:01
  • 65

高效链表排序-归并算法

排序算法应该是最基础的了,快速、归并、选择、堆排序等等对于数组而言可以随机访问,那么对于链表呢,比如快排,两个指针分别网后往前走,而没有前驱指针的单向链表,无法完成这样的操作,当然了可以采用快慢指针的...
  • wejoncy
  • wejoncy
  • 2016年05月03日 11:45
  • 2021

用归并排序对链表进行排序

当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事...
  • lalor
  • lalor
  • 2012年04月06日 00:24
  • 15299

排序算法系列:归并排序算法

上一篇我们说了一个非常简单的排序算法——选择排序。其复杂程序完全是冒泡级的,甚至比冒泡还要简单。今天要说的是一个相对比较复杂的排序算法——归并排序。复杂的原因不仅在于归并排序分成了两个部分进行解决问题...
  • u013761665
  • u013761665
  • 2016年05月27日 16:32
  • 10664

排序算法(2)——归并排序

归并排序(Merge Sort)    (1)算法思想              归并排序采用了分治策略(divide-and-conquer),就是将原问题分解为一些规模较小的相似子问题,然后递归解...
  • tmylzq187
  • tmylzq187
  • 2016年07月03日 17:48
  • 19459

白话经典算法系列之五 归并排序的实现(讲的真好)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较...
  • yuehailin
  • yuehailin
  • 2017年04月03日 16:25
  • 18015

归并排序(递归实现和迭代实现)

//首先是递归实现的方式#include #define MAXSIZE 10 //实现归并,并把数据都放在list1里面 void merging(int *list1,int list1_si...
  • chencangui
  • chencangui
  • 2015年03月27日 17:55
  • 3838

八大排序算法详解——归并排序

基本思想n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果: 初始状态:无序区为R[1..n],有序区为空。 第1趟排序: 在无序区R[1..n]中选出关键字最小的记录R[k],将它与...
  • cy__dream
  • cy__dream
  • 2017年02月08日 20:25
  • 1808

数据结构——归并排序算法

昨天说了快速排序,今天来讲一讲归并排序:什么是归并?归并:将两个或两个以上的有序表组合成一个新有序表。归并操作的步骤: 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 设定两个指...
  • u013271921
  • u013271921
  • 2015年05月26日 14:33
  • 7130
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数组和链表的归并排序算法实现(C语言)
举报原因:
原因补充:

(最多只允许输入30个字)