实现二路归并排序算法

将两个按值有序序列合并成一个按值有序序列,则称之为二路归并排序。

/**
*    实验题目:
*        实现二路归并排序算法
*    实验目的:
*        领会二路归并排序的过程和算法设计
*    实验内容:
*        设计程序,实现二路归并排序算法。用相关数据进行测试,并
*    输出各趟的排序结果。
*/


#include <stdio.h>

#include <malloc.h>
 

#define MAX_LEN     (100)                       //  最大长度

typedef int key_type;                           //  定义关键字类型为int
typedef char info_type;
typedef struct
{
    key_type key;                               //  关键字项
    info_type data;                             //  其他数据项,类型为info_type
}rec_type;                                      //  查找元素的类型

/*-----------------x和y交换------------------*/
void swap_rec(rec_type &x, rec_type &y)         //  引用类型
{
    rec_type tmp = x;
    x = y;
    y = tmp;
}

/*-----------------创建顺序表------------------*/
void create_list(rec_type recs[], key_type keys[], int n)
{
    int i;

    for(i = 0; i < n; i++)                      // recs[0...n-1]存放排序记录
        recs[i].key = keys[i];
}

/*-----------------输出顺序表------------------*/
void disp_list(rec_type recs[], int n)
{
    int i;

    for(i = 0; i < n; i++)
        printf("%d ", recs[i].key);

    printf("\n");
}

/*-----------------以下运算针对堆排序的程序------------------*/
/*-----------------创建顺序表------------------*/
void create_list1(rec_type recs[], key_type keys[], int n)
{
    int i;

    for(i = 1; i <= n; i++)                     // recs[1...n]存放排序记录
    {
        recs[i].key = keys[i - 1];
    }
}

/*-----------------输出顺序表------------------*/
void disp_list1(rec_type recs[], int n)
{
    int i;

    for(i = 1; i <= n; i++)
    {
        printf("%d ", recs[i].key);
    }
    printf("\n");
}

int cnt = 1;                                            //  全局变量

/**
*   一次归并:
*       将两个有序表recs[low...mid]和recs[mid+1...high]归并为一个有序表recs[low...high]
*
*/
static void merge_recs(rec_type recs[], int low, int mid, int high)
{
    rec_type *rec1;
    int i = low;
    int j = mid + 1;
    int k = 0;                                                              //  k是rec1的下标,i,j分别为第1、2段的下标

    printf("low = %d, mid = %d, high = %d\n", low, mid, high);
    rec1 = (rec_type *)malloc((high - low + 1) * sizeof(rec_type));         //  动态分配空间
    while(i <= mid && j <= high)
    {
        if(recs[i].key <= recs[j].key)                                      //  将第1段中的记录放入rec1中
        {
            rec1[k] = recs[i];
            i++;
            k++;
        }
        else                                                                //  将第2段中的记录放入rec1中
        {
            rec1[k] = recs[j];
            j++;
            k++;
        }
    }

    while(i <= mid)                                                         //  将第1段余下部分复制到rec1
    {
        rec1[k] = recs[i];
        i++;
        k++;
    }

    while(j <= high)                                                        //  将第2段余下部分复制到rec1
    {
        rec1[k] = recs[j];
        j++;
        k++;
    }

    for(k = 0, i = low; i <= high; k++, i++)                                //  将rec1复制回recs中
        recs[i] = rec1[k];
}

/*----------------实现有序表长度为len的一趟归并----------------*/
static void merge_pass(rec_type recs[], int len, int n)
{
    int i;

    printf("第%d趟归并:\n", cnt++);
    for(i = 0; i + 2 * len - 1 < n; i = i + 2 * len)    //  归并len长的两相邻子表
    {
        printf("recs[%d,%d]和recs[%d,%d]归并:  ", i, i + len - 1, i + len, i + 2 * len - 1);
        merge_recs(recs, i, i + len - 1, i + 2 * len - 1);
    }

    if(i + len - 1 < n - 1)                             //  余下两个子表,后者长度小于len
    {
        printf("*recs[%d,%d]和recs[%d,%d]归并:  ", i, i + len - 1, i + len, n - 1);
        merge_recs(recs, i, i + len - 1, n - 1);        //  归并这两个子表
    }

    printf("\n归并结果: ");
    disp_list(recs, n);                                 //  输出该趟的排序结果
}

/*----------------二路归并排序算法-------------------*/
static void merge_sort(rec_type recs[], int n)
{
    int len;

    for(len = 1; len < n; len = 2 * len)                //  len = 1, 2, 4, 8
        merge_pass(recs, len, n);
}

int main(int argc, char *argv[])
{
    int n = 11;
    rec_type recs[MAX_LEN];
    key_type a[] = {18, 2, 20, 34, 12, 32, 6, 16, 5, 8, 1};

    create_list(recs, a, n);
    printf("排序前: ");
    disp_list(recs, n);
    merge_sort(recs, n);
    printf("排序后: ");
    disp_list(recs, n);

    return 0;
}

测试结果:

排序前: 18 2 20 34 12 32 6 16 5 8 1
第1趟归并:
recs[0,0]和recs[1,1]归并:  low = 0, mid = 0, high = 1
recs[2,2]和recs[3,3]归并:  low = 2, mid = 2, high = 3
recs[4,4]和recs[5,5]归并:  low = 4, mid = 4, high = 5
recs[6,6]和recs[7,7]归并:  low = 6, mid = 6, high = 7
recs[8,8]和recs[9,9]归并:  low = 8, mid = 8, high = 9

归并结果: 2 18 20 34 12 32 6 16 5 8 1
第2趟归并:
recs[0,1]和recs[2,3]归并:  low = 0, mid = 1, high = 3
recs[4,5]和recs[6,7]归并:  low = 4, mid = 5, high = 7
*recs[8,9]和recs[10,10]归并:  low = 8, mid = 9, high = 10

归并结果: 2 18 20 34 6 12 16 32 1 5 8
第3趟归并:
recs[0,3]和recs[4,7]归并:  low = 0, mid = 3, high = 7

归并结果: 2 6 12 16 18 20 32 34 1 5 8
第4趟归并:
*recs[0,7]和recs[8,10]归并:  low = 0, mid = 7, high = 10

归并结果: 1 2 5 6 8 12 16 18 20 32 34
排序后: 1 2 5 6 8 12 16 18 20 32 34

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值