交换排序

交换排序

定义:根据两个关键字的比较结果来对换两个关键字在待排序列中的位置

冒泡排序:

void bubblesort(elemtype A[], int n)//冒泡排序
{
	int m,j,flag;// m表示排序趟数,j表示比较次数,flag表示是否发生了交换,即待排序列已有序。
	for(m=1; m<=n-1&&flag=1; m++)//排序n-1趟且发生了交换
	{
		flag=0;					//初始将flag置为零
		for(j=1; j>=n-m; j++)    //第m趟需比较n-m次
			if(A[j]>A[j+1])      //前后两个比较是否需要交换
			{
				swap(A[j],A[j+1]);
				flag=1;           //发生了交换
			}
	}	
}

最好情况:待排序列已有序
比较次数:n-1
交换次数:0
最坏情况:待排序列逆序
比较次数:n-i的累加和
交换次数:3(n-i)的累加和,swap函数需要交换3次才能达到交换两关键字的目的
时间复杂度 :O(n^2)
空间复杂度:O(1)
稳定性:稳定
特点: 每一趟排序必定得到一个最大或最小值放置在最终的位置上。

快速排序:

void quicksort(elemtype A[], int low,int high)//快速排序
{
	int pivotposition = partition(A[],low,high)//得到枢纽值(之前为在第一个位置上)新的位置,将左右分为两个子区间
	quicksort(A[],low,pivotposition-1);//对左区间的待排序列递归进行快速排序
	quicksort(A[],pivotposition+1,high);//对右区间的待排序列递归进行快速排序
}
int partition(elemtype A[],int low, int high)//按枢纽值划分待排序序列
{
	int pivot=A[low];       //初始枢纽值定义为区间上的第一个元素
	while(low<high)         
	{
		while(low<high&&A[high]>=pivot)//找到从右往左第一个比枢纽值小的数的位置
			high--;
		swap(A[low],A[high]);           //把该小值交换到前面去
		while(low<high&&A[low]<=pivot)//找到从左往右第一个比枢纽值大的数的位置
			low++;
		swap(A[high],A[low])             //把该大值交换到后面去
	}                                    //再找剩下的最大最小,直到high=low停止
	A[low]=pivot;
	return low;                          //返回枢纽值的位置
}

所用递归栈的深度
最好情况:树深度最小。O(log2(n+1))
最坏情况:树深度最大、O(n-1)
空间复杂度
O(log2n)
时间复杂度: 运行时间与枢纽值的选择有关,如果对称的话,时间最短为O(nlog2n)
最坏情况:初始序列有序时,退化为未优化的冒泡算法。时间复杂度O(n2)
稳定性
不稳定,当都在枢纽值一边有两个相同值时,后一个值可能先交换到左边,相对位置就发生了改变
特点
每排一趟,都会将一个枢纽值放在最终位置。(适用与寻找第几大元素第几小元素的性质)

一些有关与交换排序的题目:

双向冒泡算法:

void bi_bubblesort(elemtype A[], int n)
{
	int i,j;
	int low=0;
	int high=n-1;
	flag=1//标志是否发生交换。
	while(low<high&&flag=1)
	{
		flag=0;
		for(i=low; i<=high-1;i++)//从前往后冒泡
			if(A[i]>A[i+1])
			{
				swap(A[i+1],A[i]);
				flag=1;
			}
		high--;//更新上界
		for(j=high; j>=low+1;j--)//从后往前冒泡
			if(A[j]<A[j-1])
			{
				swap(A[j-1],A[j]);
				flag=1;
			}
		low++;//更新下界
	}					//low=high时跳出,此时待排序列中仅有一个元素
}

对于一个顺序表每个元素不同,要将奇数放在前面。偶数放在后面。
首先:对于这样一个问题,想到交换算法快速排序的划分方法,扫描一边即可。

void oddnum(elemtype A[], int n)
{
	int low=0;
	int high=n-1;
	while(low<high)//当只剩下一个关键字时排序完成
	{	
		while(low<high&&A[high]%2==0)//从右往左找到第一个奇数,且不能比low小
			high--;	
		while(low<high&&A[low]%2==1)//从左往右找第一个偶数,且不能比high高
			low++;
		if(low<high)				//判断到底是找到了还是出界了
		{
			swap(A[high],A[low])//将右边的奇数和左边的偶数交换
			low++;     //再找下一区间的
			high--;
		}
	}
}

**将红黄蓝三种颜色组成的序列,排序后顺序为红黄蓝。**同理可以对应不同的三个数排序
首先,对于这种情况可以采用交换算法,一个指针保存红色位置。一个指针保存蓝色的位置。
一个指针用来扫描所有关键字

typedef enum            // 建立一个包括这三种元素的数据结构
{
	red,yellow,blue
}color
void redyellowblue(color[],int n)
{
	int i=0;
	int low =0;
	int high =n-1;
	while (i<=high)       //将所有n个关键字扫描一遍
	{
		switch(color[i])
			case red:          
				swap(color[i],color[low]);  //如果是红色,把他保存到红色的位置上去,交换回来的关键字一定不是红色。
				low++;
				i++;          //所以指针下移一位,而不用判断他是否是红色。
				break;
			case yellow:   //黄色不用管他,直接下移一位
				i++;
				break;
			case blue:     
				swap(color[i],color[high]);  //如果是蓝色,把他放到蓝色的位置上去,但是交换回来的数据不知道是什么颜色
				high--;	//所以蓝色位置指针位置改变。而扫描指针不下移,继续判断是什么颜色。
			}
	}
}

从无序线性表中找第K小的关键字。
思考,有三种方法
第一种:先排序后找第k个位置上的数,最低时间复杂度0nlog2n
第二种:采用选择排序中的小顶堆排序,输出第k个关键字即是第k小的关键字。时间复杂度0 n+klog2n
第三种:采用快排中的划分方法,当枢纽值的位置m=k时即为第k小的值,如果m<k,则第k小的值在枢纽右边子序列。同理m>k。

int k_num(elemtype A[], int low, int high, int k)
{
	int pivot=A[low];
	int low_temp=low;					//递归需要更改上下界,所以把设置变量
	int high_temp=high;
	
	while(low_temp<high_temp)			//快排的划分算法
	{
		while(low_temp<high_temp&&A[high_temp]>=pivot)
			high_temp--;
		swap(A[low_temp],A[high_temp]);
		while(low_temp<high_temp&&A[low_temp]<=pivot)
			low_temp++;
		swap(A[high_temp],A[low_temp]);
	}
	A[low_temp]=pivot;
	if(low_temp=k)					//第k个位置,正好。
		return A[low_temp];
	else if(low_temp<k)               
		k_num(A[],low_temp+1,high,k-low_temp); //从右区间找,注意此时找的是第k-low小值
	else
		k_num(A[],low,low_temp-1,k);//从左区间找第k大的值。
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值