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

原创 2012年03月25日 22:51:51

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;
}



相关文章推荐

数据结构 JAVA描述(十二) 归并排序 链式基数排序

归并排序 /** * @description 2-路归并排序算法 归并过程中引入数组temp[],第一趟由a归并到temp,第二趟由temp归并到a,如此反复直到n个记录为一个有序...

python数据结构学习笔记-2016-11-24-02-基数排序

12.4 基数排序          基数排序(radix sort)是一种只适用于数字或字母类型的排序方法,它检查数字或字母的每一位,将之分类,按照位数的特定顺序,来将元素排列。        ...

数据结构与算法从零开始系列:冒泡排序、选择排序、插入排序、希尔排序、堆排序、快速排序、归并排序、基数排序

本篇内容包含 排序的介绍 排序的C的实现 排序的Java的实现 排序的时间复杂度的计算 (一)冒泡排序1、基本思想:两个数比较大小,较大的数下沉,较小的数冒起来2、实现步骤:这张图就是将数字12,35...

[C++]数据结构:排序算法Part2----快速排序、归并排序、箱子排序、基数排序

接上篇博文: [C++]数据结构:排序算法Part1----冒泡排序、选择排序、插入排序、堆排序 5.快速排序: 快速排序的核心思想是分而治之算法。所谓的分而治之,简单来说就是把...

数据结构--排序算法(归并排序&&基数排序&&桶排序)

在前面我们说了快速排序等排序方法,如有同学想看则请查阅往期博: 插入排序,选择排序:http://blog.csdn.net/sayhello_world/article/details/619270...

python数据结构学习笔记-2016-11-23-01-归并排序

12.1 归并排序         排序算法分为两大类:比较排序和分布排序         比较排序(comparsion sort):数据可以通过排序关键字的逻辑关系比较来实现升序或降序排列。这...

【数据结构】基数排序的哈希表

  • 2010年08月09日 05:45
  • 23KB
  • 下载

经典排序算法设计与分析(插入排序、冒泡排序、选择排序、shell排序、快速排序、堆排序、分配排序、基数排序、桶排序、归并排序)

经典的内排序算法有: 插入排序、冒泡排序、选择排序、shell排序、快速排序、堆排序、分配排序、基数排序、桶排序 为了分析所有的排序情况,给出一个模板程序用于测试,通过改写mySort函数来实现不同的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数据结构学习笔记 --- 排序(归并排序、基数排序)
举报原因:
原因补充:

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