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

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



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

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

【数据结构】-归并排序,基数排序

归并排序思想:基数排序思想:
  • tailyou
  • tailyou
  • 2015年09月01日 21:21
  • 310

数据结构-基数排序(桶排序)

基数排序和计数排序都属于“非比较排序”,有关计数排序可查看http://blog.csdn.net/sssssuuuuu666/article/details/78677302。 基数排序介绍: ...
  • sssssuuuuu666
  • sssssuuuuu666
  • 2017年12月15日 13:56
  • 319

各种常见的排序,冒泡排序,选择排序,插入排序,希尔排序,堆排序,快速排序,基数排序,桶排序

各种常见的排序 要开始找工作了,把以前学的各种小知识复习一遍,以下是各种常见的排序的简单实现(冒泡排序,选择排序,插入排序,希尔排序,堆排序,快速排序,基数排序,桶排序),至于原理就不写出来了,...
  • xwchao2014
  • xwchao2014
  • 2015年08月04日 16:41
  • 949

数据结构系列之基数排序

本文详细介绍了基数排序的原理及实现过程
  • fengyinchao
  • fengyinchao
  • 2015年06月08日 14:41
  • 1398

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

1. 引言  本文主要讲解一些常见的排序算法。 2. 归并排序   归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conque...
  • gzw1623231307
  • gzw1623231307
  • 2017年02月22日 07:10
  • 56

插入排序、交换排序、选择排序、归并排序、基数排序

插入排序 每一趟将一个待排序的记录,按照其关键字的大小插入到有序队列的合适位置里,知道全部插入完成。 不同插入排序算法的最根本的不同点是根据什么规则寻找新元素的插入点,直接插入排序采用依次寻找,而折半...
  • fandoudou123
  • fandoudou123
  • 2016年03月25日 20:04
  • 562

排序算法----冒泡排序+插入排序+选择排序+快速排序+希尔排序+堆排序+归并排序+计数排序+基数排序+桶排序(c语言)

c语言实现各种排序算法
  • zlhzlh11
  • zlhzlh11
  • 2015年10月14日 15:18
  • 1607

CUDA(六). 从并行排序方法理解并行化思维——冒泡、归并、双调排序的GPU实现

在第五讲中我们学习了GPU三个重要的基础并行算法: Reduce, Scan 和 Histogram,分析了 其作用与串并行实现方法。 在第六讲中,本文以冒泡排序 Bubble Sort、归并排序 ...
  • abcjennifer
  • abcjennifer
  • 2015年09月14日 19:09
  • 21120

【数据结构与算法】内部排序之四:归并排序和快速排序(含完整源码)

之所以把归并排序和快速排序放在一起探讨,很明显两者有一些相似之处:这两种排序算法都采用了分治的思想。下面来逐个分析其实现思想。 归并排序 实现思想 归并的含义很明显就是将两...
  • mmc_maodun
  • mmc_maodun
  • 2014年03月06日 00:02
  • 7426
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数据结构学习笔记 --- 排序(归并排序、基数排序)
举报原因:
原因补充:

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