交换排序


鸡尾酒排序 等于是冒泡排序的轻微变形。不同的地方在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。

以序列(2,3,4,5,1)为例,鸡尾酒排序只需要访问一次序列就可以完成排序,但如果使用冒泡排序则需要四次。

复杂度

鸡尾酒排序最糟或是平均所花费的次数都是O(n2),但如果序列在一开始已经大部分排序过的话,会接近O(n)


#include <iostream>
using namespace std;

void swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
/*
鸡尾酒排序,也就是定向冒泡排序, 鸡尾酒搅拌排序, 搅拌排序 (也可以视作选择排序的一种变形),
 涟漪排序, 来回排序 or 快乐小时排序, 是冒泡排序的一种变形。
 此算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。
*/
void cocktail_sort(int A[],int len)
{
	bool flag = true;
	int i;
	int times =1;
	while(flag)
	{
		flag = false;
		for(i=0;i<len-times;i++)
		{
			if(A[i]>A[i+1])
			{
				swap(A[i],A[i+1]);
				flag = true;
			}
		}
		times++;
	
		for(i=len-times;i>1;i--)
		{
			if(A[i]<A[i-1])
				swap(A[i],A[i-1]);
		}
		
	}
	cout<<times<<endl;    //普通的冒泡排序需要17次,而此鸡尾酒法只需8次
}

/*
------奇偶排序法---------
重复两趟扫描。第一趟扫描选择所有的数据项对,a[j]和a[j+1],j是奇数(j=1, 3, 5……)。
如果它们的关键字的值次序颠倒,就交换它们。
第二趟扫描对所有的偶数数据项进行同样的操作(j=2, 4,6……)。
重复进行这样两趟的排序直到数组全部有序。
*/
void oddEvenSort(int A[],int len)
{
	bool flag = true;
	int times = 0;
	int i;
	while(flag)
	{
		flag = false;
		for(i=times%2;i<len-1;i=i+2)
		{
			if(A[i]>A[i+1])
			{
				swap(A[i],A[i+1]);
				flag = true;
			}
		}
		times++;
	}
	cout<<times++<<endl;
}

/*
梳排序中,
开始时的间距设定为阵列长度,并在循环中以固定比率递减,通常递减率设定为1.3。
在一次循环中,梳排序如同泡沫排序一样把阵列从首到尾扫描一次,比较及交换两项,不同的是两项的间距不固定于1。
如果间距递减至1,梳排序假定输入阵列大致排序好,并以泡沫排序作最后检查及修正。
*/
void combsort(int A[],int len)
{
	float shrink_factor = 1.3;   //1.247330950103979;
	int gap = len;
	int i;
	while(gap>0)
	{
		gap = gap/shrink_factor;
		for(i=0;i<len-gap;i++)
		{
			if(A[i]>A[i+gap])
			{
				swap(A[i],A[i+gap]);
			}
		}
	}
}

/*
	-----------地精排序----------

	Current array	Action to take
	[5, 3, 2, 4]	a[pos] < a[pos-1], swap:
	[3, 5, 2, 4]	a[pos] >= a[pos-1], increment pos:
	[3, 5, 2, 4]	a[pos] < a[pos-1], swap and pos > 1, decrement pos:
	[3, 2, 5, 4]	a[pos] < a[pos-1], swap and pos <= 1, increment pos:
	[2, 3, 5, 4]	a[pos] >= a[pos-1], increment pos:
	[2, 3, 5, 4]	a[pos] < a[pos-1], swap and pos > 1, decrement pos:
	[2, 3, 4, 5]	a[pos] >= a[pos-1], increment pos:
	[2, 3, 4, 5]	a[pos] >= a[pos-1], increment pos:
	[2, 3, 4, 5]	pos == length(a), finished.
*/
void gnomeSort(int A[],int len)
{
	int i;
	if(A[0]>A[1]) swap(A[0],A[1]);
	for(i=1;i<len-1;i++)
	{
		if(A[i]>A[i+1])
		{
			swap(A[i],A[i+1]);
			i=i-2;
		}
	}
}

/*
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

步骤为:
①从数列中挑出一个元素,称为 "基准"(pivot),
②重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
③递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

    递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。
虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
*/

int Partition(int A[],int low,int high)
{
	int pivokey = A[low];
	while(low<high)
	{
		while(low<high && A[high]>=pivokey) high--;       //必须要有“=”否则同样大小的数就没人要了!
		A[low]=A[high];
		while(low<high && A[low]<=pivokey) low++;
		A[high]=A[low];
	}
	A[low]=pivokey;
	return low;
}

void quickSort(int A[],int low,int high)
{
	int pivotloc;
	if(low<high)
	{
		pivotloc = Partition(A,low,high);
		//cout<<"pivotloc:"<<pivotloc<<"   A[pivotloc]:"<<A[pivotloc]<<endl;
		quickSort(A,low,pivotloc-1);
		quickSort(A,pivotloc+1,high);
	}
}

int main()
{
	//int A[]={15,9,8,1,4,11,7,2,13,16,5,3,6,2,10,14};
	int A[]={13,14,94,33,82,25,59,94,65,23,45,27,73,25,39,10,35,54,90,58};
	int i;
	int len=sizeof(A)/sizeof(int);     //在这里 sizeof(array)=80 
	//oddEvenSort(A,len);
	//combsort(A,len);
	//gnomeSort(A,len);
	//cocktail_sort(A,len);
	quickSort(A,0,len-1);
	for(i=0;i<len;i++)
	{
		cout<<A[i]<<"  ";
	}
	cout<<endl;
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值