数据结构学习笔记 --- 排序(归并排序、基数排序)

1. 引言 


本文主要讲解一些常见的排序算法。


2. 归并排序

  归并排序是建立在归并操作上的一种有效的 排序 算法。该算法是采用 分治法 (Divide and Conquer)的一个非常典型的应用。

  将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。


归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。

  如 设有数列{6,202,100,301,38,8,1}
  初始状态: [6] [202] [100] [301] [38] [8] [1] 比较次数
  i=1 [6 202 ] [ 100 301] [ 8 38] [ 1 ] 3
  i=2 [ 6 100 202 301 ] [ 1 8 38 ] 4
  i=3 [ 1 6 8 38 100 202 301 ] 4
  总计: 11次


 复杂度:时间O(nlogn)

  空间O(n)
  与快速排序类似。


归并排序是稳定的排序.即相等的元素的顺序不会改变.如输入记录 1(1) 3(2) 2(3) 2(4) 5(5) (括号中是记录的关键字)时输出的 1(1) 2(3) 2(4) 3(2) 5(5) 中的2 和 2 是按输入的顺序.这对要排序数据包含多个信息而要按其中的某一个信息排序,要求其它信息尽量按输入的顺序排列时很重要.这也是它比快速排序优势的地方.


#include "ds.h"

#define 	MAX_SIZE 	20			// 一个用作示例的小顺序表的最大长度
typedef		int			KeyType;	// 定义关键字类型为整型
typedef 	int 		InfoType; // 定义其它数据项的类型

#define 	EQ(a,b) 	((a)==(b))
#define 	LT(a,b) 	((a)<(b))
#define 	LQ(a,b) 	((a)<=(b))

struct RedType						// 记录类型
{
	KeyType		key;				// 关键字项
	InfoType	otherinfo;			// 其它数据项,具体类型在主程中定义
};

struct SqList						// 顺序表类型
{
	RedType		r[MAX_SIZE+1];		// r[0]闲置或用作哨兵单元
	int 		length;				// 顺序表长度
};


void Merge(RedType SR[],RedType TR[],int i,int m,int n)
{ // 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] 算法10.12
  int j,k,l;
  for(j=m+1,k=i;i<=m&&j<=n;++k) // 将SR中记录由小到大地并入TR
    if LQ(SR[i].key,SR[j].key)
      TR[k]=SR[i++];
    else
      TR[k]=SR[j++];
  if(i<=m)
    for(l=0;l<=m-i;l++)
      TR[k+l]=SR[i+l]; // 将剩余的SR[i..m]复制到TR
  if(j<=n)
    for(l=0;l<=n-j;l++)
      TR[k+l]=SR[j+l]; // 将剩余的SR[j..n]复制到TR
}

void MSort(RedType SR[],RedType TR1[],int s, int t)
{ // 将SR[s..t]归并排序为TR1[s..t]。算法10.13
  int m;
  RedType TR2[MAX_SIZE+1];
  if(s==t)
    TR1[s]=SR[s];
  else
  {
    m=(s+t)/2; // 将SR[s..t]平分为SR[s..m]和SR[m+1..t]
    MSort(SR,TR2,s,m); // 递归地将SR[s..m]归并为有序的TR2[s..m]
    MSort(SR,TR2,m+1,t); // 递归地将SR[m+1..t]归并为有序的TR2[m+1..t]
    Merge(TR2,TR1,s,m,t); // 将TR2[s..m]和TR2[m+1..t]归并到TR1[s..t]
  }
}

void MergeSort(SqList &L)
{ // 对顺序表L作归并排序。算法10.14
  MSort(L.r,L.r,1,L.length);
}

void print(SqList L)
{
  int i;
  for(i=1;i<=L.length;i++)
    printf("(%d,%d)",L.r[i].key,L.r[i].otherinfo);
  printf("\n");
}

#define N 7
int main()
{
  RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7}};
  SqList l;
  int i;
  for(i=0;i<N;i++)
    l.r[i+1]=d[i];
  l.length=N;
  printf("排序前:\n");
  print(l);
  MergeSort(l);
  printf("排序后:\n");
  print(l);
}


求逆序数


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

//
//求逆序数
//最快的算法是归并排序时计算逆序个数,时间复杂度是nlog2n, 空间复杂度是2n
//a为字符数组,len为字符数组的长度
int number = 0; //number表示逆序对的个数
void mergePass(char *, char *, int, int);
void merge(char*, char*, int, int, int);
void copy(char *dest, char *src, int l, int r)
{
    while(l <= r)
    {
        dest[l] = src[l];
        l++;
    }
}
void mergeSort(char *a, int size)
{
    char *b = (char*)malloc(sizeof(char) * size);
    mergePass(a, b, 0, size - 1);
    free(b);
}


void mergePass(char *a, char *b, int l, int r)
{
    int m;
    if(l < r)
    {
        m = (l + r) / 2;
        mergePass(a,b,l,m);
        mergePass(a,b,m+1,r);
        merge(a,b,l,m,r);
        copy(a,b,l,r);

    }
}

void merge(char *a, char *b, int l, int m, int r)
{
    int i = l, j = m + 1;
    while( i <= m && j <= r)
    {
        if(a[i] <= a[j])
            b[l++] = a[i++];
        else
        {
            b[l++] = a[j++];
                        //a[i] > a[j], 表示出现了逆序对,此时由于
                        //a[i..m]是已经有序了,那么a[i+1], a[i+2], ... a[m]都是大于a[j]的,
                        //都可以和a[j]组成逆序对,因此number += m - i + 1
            number += m-i+1;
        }
    }
    while(i <= m)
        b[l++] = a[i++];
    while(j <= r)
        b[l++] = a[j++];
}


int main()
{
    char a[10] = {'A','A','C','A','T','G','A','A','G','G'};
    char b[5] = {'A', 'B', 'A', 'A','A'};
    mergeSort(b, 5);
    for(int i = 0; i < 10; i++)
        printf("%c ",a[i]);
    printf("%d ", number);
    system("pause");
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值