插入,希尔,快速排序

预备知识:基于比较的排序本质就是将序列中所有的逆序消除.一个排序好的序列是没有逆序的.
    定理:N个互异数的数组的平均逆序数是N(N-1)/4.
通过交换相邻元素进行排序的任何算法平均时间复杂度为N^2.
(因为每次交换只减少一个逆序,而初始的平均逆序数是N(N-1)/4==>时间复杂度为N^2)

1)插入排序 ,冒泡排序,选择排序==>交换相邻元素的方法
//下面只贴出插入排序程序
//两种实现一样.第一种容易理解,但是花去了更多的时间.第二种是对第一种的优化.
void InsertionSort(ElementType A[], int N)
{
	int j, P;
	ElementType Tmp;
	for(P = 1; P < N; P ++ )
	{
		for( j = P; j > 0; j -- )
		{
			if( A[ j - 1 ] > A[ j ] )
			{
				Tmp = A[ j ];
				A[ j ] = A[ j - 1 ];
				A[ j - 1 ] = Tmp;
			}
		}
	}
}

void InsertionSort(ElementType A[], int N)
{
	int j,P;
	ElementType Tmp;
	for( P = 1; P < N; P ++ )
	{
		Tmp = A[ P ];
		for( j = P; j > 0 && A[ j - 1 ] > Tmp; j -- )
			A[ j ] = A[ j - 1 ];
		A[ j ] = Tmp;
	}
}

2)希尔排序
原理:通过比较相距一定间隔的元素来工作;隔趟比较所用的距离随着算法的进行而减少,
直到只比较相邻元素的最后一趟排序为止.由于这个原因,希尔排序也叫缩小增量排序.
Shell建议的序列是:H = [N/2];实践中最好的序列之一是{1,5,19,109 .....}也就是 4^i - 3*2^i + 1.
通过将这些值放到数组中可以很容易实现该算法.
//增量为H=N/2
void Shellsort(ElementType A[], int N )
{
	int i, j, Increment;
	ElementType Tmp;
	for( Increment = N / 2; Increment > 0; Increment /= 2 )
	{
		for( i = Increment; i < N; i ++ )
		{
			for( j = i; j >= Increment; j -= Increment )
			{
				if( A[ j ] < A[ j - Increment ] )
				{
					Tmp = A[ j ];
					A[ j ] = A[ j - Increment ];
					A[ j - Increment ] = Tmp;
				}
				else 
					break;
			}
		}
	}
}
3)快速排序
原理:随机的(一般用三数中值分割法)选取枢纽元,集合中其余元素分成两个更小的集合.
大于枢纽元的放到一个集合,小于枢纽元的放到另一个集合.然后递归地将两个子集合排序.
对于很小的数组(N<=20)快速排序不如插入排序好.因为快速排序是递归的,所以这种情况免不了要发生.
通常解决的方法是对于小的数组不递归地使用快速排序,而是用插入排序.
void Swap( ElementType *Left, ElementType *Right )
{
	ElementType Tmp = *Left;
	*Left = *Right;
	*Right = Tmp;
}

//三数中值分割法获取枢纽
//例如:1 3 6 4 2,它的左边元素是1,右边是2,中间元素是6.所以中值自然是2.
//
ElementType Median3( ElementType A[] ,int Left, int Right )
{
	int Center = (Left + Right ) / 2;
	if(A[ Left ] > A[ Center ])
		Swap(&A[Left],&A[Center]);
	if(A[Left] > A[Right])
		Swap(&A[Left],&A[Right]);
	if(A[Center] > A[Right])
		Swap(&A[Center],&A[Right]);//1 3 2 4 6
	Swap(&A[Center],&A[Right - 1]);//将枢纽元存放到A[Right - 1]的位置,方便快速排序的元素的分割. 1 3 4 2 6
	return A[Right - 1];//返回枢纽元 2
}

#define Cutoff (20)
void Qsort( ElementType A[], int Left, int Right )
{
	int i,j;
	ElementType Pivot;
	if( Left + Cutoff <= Right )//限定使用快速递归排序的元素个数不小于Cutoff,否则使用插入排序.
	{
		Pivot = Median3(A,Left,Right);
		i = Left; j = Right - 1;
		for(;;)//分割实现:将所有小于枢纽元的元素移动到数组左边,所有大元素移动到数组的右边.
		{//分割停止时,i指向一个大元素,j指向一个小元素.
			while(A[++i] < Pivot){}//i遇到>=Pivot的元素时,跳出循环,准备交换
			while(A[--j] > Pivot){}//j遇到<=Pivot的元素时,跳出循环,准备交换
			if( i < j)
				Swap(&A[i],&A[j]);
			else
				break;
		}
		Swap(&A[i],&A[Right - 1]);//分割的最后一步是将枢纽元与i所指向的元素交换.
		Qsort(A,Left,i - 1);//对分割好的子集合进行快速递归排序
		Qsort(A,i + 1, Right );
	}
	else  //使用插入排序
		InsertionSort(A + Left, Right - Left + 1);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值