若干常用(内部)排序算法的总结

10 篇文章 0 订阅

实现代码中会出现宏

typedef int DataType;
#define SWAP( A, B )   {DataType x = A; A = B; B = x;}

1. 插入排序算法

类似数学归纳法的描述:

① 起始时A[beg]的元素位置不变(此时A[beg]这一个元素已经有序)

② 假设A[beg]..A[i](beg<=i<=end-1)已经排好序, 对A[i+1]..A[end],依次将A[i+1],...,A[end]插入到A[beg],...,A[i]的指定位置

将①②结合可得到插入排序的伪代码:

  for i=beg+1:1:end
      t = A[i]
      for j=i-1:-1:beg
          if t < A[j]
              A[j+1] = A[j]
          else
              break
      A[j+1] = t

void InsertSort( DataType* A, int beg, int end )
{
	int i, j;
	int k;
	DataType t;

	for ( i = beg+1; i <= end; ++i )
	{
		t = A[i];
		for ( j = i-1; j >= beg; --j )
		{
			if ( A[j] > t )
			{
				A[j+1] = A[j];
			}
			else
			{
				break;
			}
		}
		A[j+1] = t;
	}
}

2.选择排序

基本思想,类似数学归纳法的描述:

① 起始时找到A[beg]..A[end]中的最小元素,将该元素与A[beg]交换;

② 假设A[beg]..A[i](beg<=i<=end-1)已经有序且A[i+1]..A[end]的任一元素大于A[beg]..A[i], 从A[i+1]..A[end]选择最小的元素添加到A[beg]..A[i]末尾,亦即将A[i+1]与A[i+1]..A[end]中的最小元素交换位置

将①②结合可得到选择排序的伪代码:

  for i=beg:1:end-1
      find k s.t. A[k] = min( A[i+1]..A[end] )
      exchange A[i] and A[k]

实现:

void SelectionSort( DataType* A, int beg, int end )
{
	int i, j, k;
	DataType m;

	for ( i = beg; i < end; ++i )
	{
		m = A[i];
		k = i;
		for ( j = i+1; j <= end; ++j )
		{
			if ( A[j] < m )
			{
				m = A[j];
				k = j;
			}
		}
		if ( k != i )
		{
			SWAP( A[i], A[k] );
		}
	}
}

3. 冒泡排序

基本思想,类似数学归纳法的描述:

① 起始进行第一轮冒泡,对A[beg]..A[end]从后往前,如果A[j-1]>A[j], 则交换A[j-1]和A[j]的值(beg<=j-1<j<=end);完成后A[beg]已经为数组中的最小元素

② 假设A[beg]..A[i](beg<=i<=end-1)已经排好序且A[i+1]..A[end]的任一元素大于A[beg]..A[i],对A[i+1]..A[end]从后往前冒泡:若A[j-1]>A[j],交换A[j-1]和A[j], (i+1<=j-1<j<=end)

将①②结合可得到冒泡排序伪代码:

  for i = beg:1:end-1
      for j = end:-1:i+1
          if A[j-1] < A[j]
              then exchange A[j-1] and A[j]

实现:

void BubbleSort( DataType* A, int beg, int end )
{
	int i, j;
	int k;

	for ( i = beg; i < end; ++i )
	{
		for ( j = end; j > i; --j )
		{
			if ( A[j-1] > A[j] )
			{
				SWAP( A[j-1], A[j] );
			}
		}
	}
}

4. 快速排序

基本思想:分治策略

首选选取一个枢纽元P,通常选取P=A[beg],将数组余下的元素通过与P比较,将原数组划分为两部分:小于P的部分和大于P的部分,然后构建新的数组,使得A[j]的元素值为P,A[beg]..A[j-1]的值全都小于P,A[j+1]..A[end]的值全部大于P;然后分别对子数组A[beg]..A[j-1]和A[j+1]..A[end]进行快速排序。

实现如下(递归版本):

void QuickSort( DataType* A, int beg, int end )
{
	int i, j;
	DataType p;

	if ( beg >= end )
		return;
	
	i = beg;
	j = end+1;
	p = A[beg];
	for ( ;; )
	{
		while( ++i <= end && A[i] < p );
		while( A[--j] > p );
		if ( i > j )
			break;
		SWAP( A[i], A[j] );
	}
	SWAP( A[j], A[beg] );

	QuickSort( A, beg, j-1 );
	QuickSort( A, j+1, end );
}

对以上基本的快速排序算法可进行一下两方面的改进:

① 枢纽元P的选择对快速排序算法的效率有很大影响,为了使得快速排序算法对所有可能情况的排序时间复杂度尽可能低,通常在数组中选取一个随机的元素作为枢纽元;具体的实现策略也很简单,就是现在数组中随机选取一个元素,然后将该元素与数组第一个元素交换,并将该元素作为枢纽元,接下来便可直接套用如下实现的算法;

② 虽然插入排序等时间复杂度为O(N^2)的算法比快速排序的平均时间复杂度O(NlogN)要大,但经过试验测试,当待排序的数据个数小于20个时,插入排序等算法的实际消耗时间比快速排序算法要小(因为快速排序算法是一个递归的算法,通常递归的效率是比较低的);因此可以考虑当快速排序递归到数组元素个数小于某一值N(N<20)时,不再采用快速排序继续递归,而是采用插入排序等算法。

随机选取枢纽元素的快速排序算法实现:

#include <stdlib.h>
#include <time.h>     // windows
void QuickSort1( DataType* A, int beg, int end)
{
	int i, j, n;
	DataType p;

	if ( beg >= end )
		return;

	srand((unsigned)time(0));     // 生成随机数种子
	n = rand()%(end-beg+1) + beg; // 生成beg..end之间的随机数
	SWAP(A[n], A[beg]);
	
	p = A[beg];
	i = beg;
	j = end+1;
	for ( ;; )
	{
		while( ++i <= end && A[i] < p );
		while( A[--j] > p );
		if ( i > j )
			break;
		SWAP( A[i], A[j] );
	}
	SWAP( A[beg], A[j] );

	QuickSort1( A, beg, j-1 );
	QuickSort1( A, j+1, end );
}

当数组元素小于16时采用插入排序算法,实现如下:

void QuickSort2( DataType* A, int beg, int end )
{
	int i, j;
	DataType p;

	if ( beg >= end )
		return;
	else if ( end - beg < 16 )
	{
		InsertSort( A, beg, end );
		return;
	}
	
	p = A[beg];
	i = beg;
	j = end+1;
	for ( ;; )
	{
		while( ++i <=end && A[i] < p );
		while( A[--j] > p );
		if ( i > j )
			break;
		SWAP( A[i], A[j] );
	}
	SWAP( A[beg], A[j] );

	QuickSort2( A, beg, j-1 );
	QuickSort2( A, j+1, end );
}

综合 QuickSort1 和 QuickSort2 的快速排序算法实现:

void QuickSort3( DataType* A, int beg, int end )
{
	int i, j, n;
	DataType p;

	if ( beg >= end )
		return;
	else if ( end - beg < 16 )
	{
		InsertSort( A, beg, end );
		return;
	}
	
	srand( (unsigned int)time(0) );
	n = rand()%(end-beg+1) + beg;
	SWAP( A[beg], A[n] );

	i = beg;
	j = end+1;
	p = A[beg];
	for ( ;; )
	{
		while( ++i <= end && A[i] < p );
		while( A[--j] > p );
		if ( i > j )
			break;
		SWAP( A[i], A[j] );
	}
	SWAP( A[beg], A[j] );

	QuickSort3( A, beg, j-1 );
	QuickSort3( A, j+1, end );
}

快速排序算法的非递归实现可参见:快速排序算法的递归与非递归实现 。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值