第十六周项目6—归并排序

#include <stdio.h>
#include <malloc.h>
#define MaxSize 20
typedef int KeyType;    //定义关键字类型
typedef char InfoType[10];
typedef struct          //记录类型
{
    KeyType key;        //关键字项
    InfoType data;      //其他数据项,类型为InfoType
} RecType;              //排序的记录类型定义

void Merge(RecType R[],int low,int mid,int high)
{
    RecType *R1;
    int i=low,j=mid+1,k=0; //k是R1的下标,i、j分别为第1、2段的下标
    R1=(RecType *)malloc((high-low+1)*sizeof(RecType));  //动态分配空间
    while (i<=mid && j<=high)       //在第1段和第2段均未扫描完时循环
        if (R[i].key<=R[j].key)     //将第1段中的记录放入R1中
        {
            R1[k]=R[i];
            i++;
            k++;
        }
        else                            //将第2段中的记录放入R1中
        {
            R1[k]=R[j];
            j++;
            k++;
        }
    while (i<=mid)                      //将第1段余下部分复制到R1
    {
        R1[k]=R[i];
        i++;
        k++;
    }
    while (j<=high)                 //将第2段余下部分复制到R1
    {
        R1[k]=R[j];
        j++;
        k++;
    }
    for (k=0,i=low; i<=high; k++,i++) //将R1复制回R中
        R[i]=R1[k];
}

void MergePass(RecType R[],int length,int n)    //对整个数序进行一趟归并
{
    int i;
    for (i=0; i+2*length-1<n; i=i+2*length)     //归并length长的两相邻子表
        Merge(R,i,i+length-1,i+2*length-1);
    if (i+length-1<n)                       //余下两个子表,后者长度小于length
        Merge(R,i,i+length-1,n-1);          //归并这两个子表
}
void MergeSort(RecType R[],int n)           //自底向上的二路归并算法
{
    int length;
    for (length=1; length<n; length=2*length) //进行log2n趟归并
        MergePass(R,length,n);
}
int main()
{
    int i,n=10;
    RecType R[MaxSize];
    KeyType a[]= {9,8,7,6,5,4,3,2,1,0};
    for (i=0; i<n; i++)
        R[i].key=a[i];
    printf("排序前:");
    for (i=0; i<n; i++)
        printf("%d ",R[i].key);
    printf("\n");
    MergeSort(R,n);
    printf("排序后:");
    for (i=0; i<n; i++)
        printf("%d ",R[i].key);
    printf("\n");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
败者树是一种数据结构,用于在多个有序序列中选择最小元素。在归并排序中,我们可以使用败者树来选择每次合并的最小元素。 以下是C语言实现败者树的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <limits.h> #define K 4 // 要归并的有序序列数量 typedef struct { int val; // 元素值 int idx; // 元素所在序列的编号 } Node; typedef struct { Node *tree; // 败者树 int *leaves; // 叶子节点,存放每个序列的当前元素 int k; // 序列数量 } LoserTree; // 初始化败者树 void init(LoserTree *lt, int *arr[]) { int i; lt->k = K; lt->tree = (Node *) malloc(sizeof(Node) * K); for (i = 0; i < K; i++) { lt->tree[i].val = INT_MIN; lt->tree[i].idx = -1; } lt->leaves = (int *) malloc(sizeof(int) * K); for (i = 0; i < K; i++) { lt->leaves[i] = i; lt->tree[i].val = arr[i][0]; lt->tree[i].idx = i; } } // 获取败者树的根节点 int getRoot(LoserTree *lt) { return lt->tree[0].idx; } // 重新调整败者树 void adjust(LoserTree *lt, int idx) { int parent, tmp; Node tmpNode; parent = (idx + lt->k) / 2; while (parent > 0) { if (lt->tree[idx].val > lt->tree[lt->leaves[parent]].val) { tmp = idx; idx = lt->leaves[parent]; lt->leaves[parent] = tmp; } parent /= 2; } lt->leaves[0] = idx; tmpNode = lt->tree[lt->leaves[0]]; for (parent = (lt->leaves[0] + lt->k) / 2; parent > 0; parent /= 2) { if (tmpNode.val > lt->tree[lt->leaves[parent]].val) { lt->tree[lt->leaves[parent]] = tmpNode; tmpNode = lt->tree[lt->leaves[parent]]; } } lt->tree[lt->leaves[0]] = tmpNode; } // 归并排序 void mergeSort(int *arr[], int n) { int i, root; int *pos = (int *) malloc(sizeof(int) * K); // 记录每个序列当前要归并的元素下标 int *res = (int *) malloc(sizeof(int) * n); // 存放归并排序后的结果 LoserTree lt; init(&lt, arr); for (i = 0; i < n; i++) { root = getRoot(&lt); res[i] = lt.tree[root].val; pos[root]++; if (pos[root] < n / K) { lt.tree[root].val = arr[root][pos[root]]; } else { lt.tree[root].val = INT_MAX; } adjust(&lt, root); } for (i = 0; i < n; i++) { printf("%d ", res[i]); } printf("\n"); free(lt.tree); free(lt.leaves); free(pos); free(res); } int main() { int *arr[K]; int a[K][10] = {{1, 3, 4, 6, 9, 13, 15, 17, 19, 20}, {2, 5, 7, 10, 12, 14, 16, 18, 21, 22}, {23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, {33, 34, 35, 36, 37, 38, 39, 40, 41, 42}}; int i, j, k; for (i = 0; i < K; i++) { arr[i] = (int *) malloc(sizeof(int) * 10); for (j = 0; j < 10; j++) { arr[i][j] = a[i][j]; } } mergeSort(arr, 40); for (i = 0; i < K; i++) { free(arr[i]); } return 0; } ``` 上述代码中,我们使用了一个 `LoserTree` 结构体来表示败者树。在 `init` 函数中,我们首先初始化了败者树的树结构和叶子节点,并将每个序列的第一个元素插入到对应的叶子节点中。在 `adjust` 函数中,我们根据当前元素的大小重新调整败者树。在归并排序中,我们首先获取败者树的根节点,即当前所有元素中的最小值,并将其存入结果数组中。然后我们将对应序列的下一个元素插入到败者树中,并调整树结构,以便下一次获取最小元素。 在实际使用中,我们可以将多个有序序列分割成若干个小块,每个小块的大小为 $B$。然后对于每个小块,我们可以使用快速排序等算法对其进行排序,在排序后将其存入磁盘中。接下来,我们从每个小块中读取第一个元素,将其插入到败者树中,并获取当前最小元素存入结果数组中。每当一个序列的所有元素都被处理完后,我们再从磁盘中读取下一个小块,重复上述过程,直到所有元素都被处理完。这样就可以避免将所有元素都加载到内存中,从而节省内存空间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值