排序算法2-快速排序、归并排序

快速排序的思路是这样的:

假如我从数组中挑出一个数(通常选为第一个数),那么我总可以利用这个数把数组分为两部分:大于这个数的部分和小于这个数的部分。然后对于这个两部分,分别重复前面的步骤,直到每一部分都只剩下2个数为止,我们可以比较出来。一看就知道是一个递归的程序,但是程序的难点在于:如何从用一个数把数组分为两个部分呢?当然。你大可以用一个比较笨的办法:搞一个临时数组,然后把比较的结果放在数组里,然后把数组在赋值给我们的数组。但是我这里用了一个比较巧妙地办法,通过一个临时变量,就解决了问题:

//利用第一个元素将数组分成两部分,左边部分大于第一个元素,右边部分小于
int part(pArrayList list, int low, int high)
{
	//临时变量,初始化为第一个元素,即分隔的那个数
	int val = list->data[low];
	while(low < high)
	{
		//从右向左走,直到遇见一个比分隔数小的数
		while(list->data[high] >= val && low < high)
			--high;
		//将这个数赋给第一个元素的位置,此时high位置就可以赋其他值了
		list->data[low] = list->data[high];
		//从左往右走,直到遇见一个比分隔数大的元素
		while( list->data[low] <= val && low < high)
			++low;
		//将这个元素赋给前面已经被保存过的high位置
		list->data[high] = list->data[low];
	}
	//整个循环结束后,low=high
	list->data[low] = val;
	return high;
}


有了这个程序,我们的排序就很简单了:

//快速排序
void quickSort(pArrayList list, int low, int high)
{
	int mid;
	if(low < high)
	{
		mid = part(list,low,high);
		quickSort(list,low,mid-1);
		quickSort(list,mid+1,high);
	}

}


仔细推敲我们也能发现,这个算法的性能依赖于每次取的分隔数。如果这个数能将数组分隔为近似等长的两部分,那么这个算法的效率会很高。如果整个数组数组是顺序排列好的或者逆序排列的,那么算法的效率就会差一些。

下面我们再看归并排序:

这个算法的思路基于如下事实:假设我已经有两个有序的数组,我肯定是可以把它们插在一起,变成一个有序的大数组的。所以这个算法分为两步:1.“归”。将一个大数组不停的分解,直到剩下2个元素,然后我会对它们排序。2.“并”。将两个排好序的2个元素的数组(或者是一个2个元素,一个1个元素)合并成一个有序的大数组。依次类推。

//归并排序
void mergeSort(pArrayList list, int low, int high)
{

	if(high == low)
		return ;
	if(low+1 == high)
	{
		if(list->data[low] > list->data[high])
		{
			int tmp = list->data[low];
			list->data[low] = list->data[high];
			list->data[high] = tmp;
		}
		return;
	}
	int mid = (high + low) /2;
	mergeSort(list, low, mid);
	mergeSort(list, mid+1,high);
	merge(list, low, mid, high);
}

//若list的low~mid,mid+1~high均有序,那么将它们合并起来以后依然有序
void merge(pArrayList list, int low, int mid, int high)
{


	int tmp;
	for(int i = low; i <= mid; ++i)
	{
		for(int j = mid+1; j <= high;++j)
		{
			if(list->data[i] > list->data[j])
			{
				//将这个元素插入到前面
				insertElem(list,i,list->data[j]);
				++mid;
				//注意,当你插入一个元素以后以后,由于前面多了一个元素,所以要删除这个元素时,需要删除j+1位置
				++j;
				deleteElem(list, j, &tmp);
				
			}
		}

	}
}

这个算法的复杂度为:O(nlogn)。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值