【数据结构---29】简单排序方法(下)

对快速排序的优化:

快排需要设置基准值,基准值的选取会出现两种极端情况,导致排序算法的性能变差

①针对基准值的选取做出优化
②针对递归的深度做出优化

方法一:三值取中法

<1>顾名思义就是取出三个基准值,选择值为中间的那一个
<2>三个基准值分为是最左边,最右边以及中间,中间位置为left+((right-left)>>1);
<3>之前的代码基于基准值key的设定为right-1,为了不做较大改动,将mid位置的元素和right-1位置元素互换

方法一代码实现:

int GetMiddleIndex(int* array, int left, int right)
{
	 int mid = left + ((right - left) >> 1);
	 
	 if (array[left] < array[right - 1])
	 {
		  if (array[mid] < array[left])
		  {
			   return left;
		  }
		  else if (array[mid]>array[right - 1])
		  {
			   return right - 1;
		  }
		  else
		  {
			   return mid;
		  }
	 }
	 else
	 {
		  if (array[mid] > array[left])
		  {
			   return left;
		  }
		  else if (array[mid] < array[right - 1])
		  {
			   return right - 1;
		  }
		  else
		  {
			   return mid;
		  }
	 }
}

方法二:调整递归深度

<1>不需要递归到只剩下一个元素才返回
<2>设置为元素个数小于16的时候,使用适合数据小,接近有序的直接插入排序

方法二代码实现:

 if (right - left > 16)
 {
	 InsertSort(array,right);
 }
 else
 {
 	int div = partion3(array, left, right);
	QuickSort(array, left, div);
	QuickSort(array, div + 1, right);
 }

快速排序的循环写法:

<1>递归的函数调用和数据结构的栈很类似,所以使用栈来辅助完成递归转变为循环
<2>首先将右边界压入栈中,在将左边界压入,这样左就在上,右就在下
<3>获取栈顶元素的顺序就是先left在right,如果栈中元素不唯一,就继续分组
<4>将新的区间压入栈中,顺序和<2>一致

代码实现:

void QucikSortNor(int* array, int size)
{
	 int left = 0;
	 int right = size;
 
	 Stack s;
	 StackInit(&s);
 
	 //栈的特性是先入后出,所以反过来压入元素,出栈的顺序就是对的
	 StackPush(&s, right);
	 StackPush(&s, left);
	 
	 //栈若不空,就对左右部分继续分别分组
	 while (StackEmpty(&s) != -1)
	 {
		  left = StackTop(&s);
		  StackPop(&s);
		  right = StackTop(&s);
		  StackPop(&s);
		  
		  if (right - left > 1)
		  {
			   int div = partion3(array, left, right);
	   
			   StackPush(&s, right);
			   StackPush(&s, div + 1);
			   StackPush(&s, div);
			   StackPush(&s, left);
		  }
	 }
}

归并排序:

递归写法先分组,在排序,有序之后再归并,然后写入临时空间,最后内存拷贝回去

<1>类似于二叉树的后序遍历
<2>先对左侧进行递归排序,在对右边进行递归排序,然后归并
<3>memcpy拷贝的时候注意参数array和tmp都要加上left,否则只能拷到左边
<4>归并的操作就是左边分组和右边分组每个元素分别比大小,小的先放入临时空间
<5>长度不一的话单独处理,把剩下的元素直接插到后面

归并的代码实现:

void MergeData(int* array, int left, int mid, int right,int* tmp)
{
		int begin1 = left;
		int end1 = mid;
		
		int begin2 = mid;
		int end2 = right;
		
		int index = left;
		
		while (begin1 < end1 && begin2 < end2)
		{
			if (array[begin1] < array[begin2])
			{
				tmp[index] = array[begin1];
				begin1++;
				index++;
			}
			else
			{
				tmp[index] = array[begin2];
				begin2++;
				index++;
			}
		}
		
		//长短不一样的情况,单独处理
		while (begin1 < end1)
		{
			tmp[index] = array[begin1];
			index++;
			begin1++;
		}
		while (begin2 < end2)
		{
			tmp[index] = array[begin2];
			index++;
			begin2++;
		}
}

递归框架:

void _MergeSort(int* array, int left, int right,int* tmp)
{
	 if (right - left > 1)
	 {
		  int mid = left + ((right - left) >> 1);
		  
		  _MergeSort(array, left, mid,tmp);
		  _MergeSort(array, mid, right,tmp);
		  
		  MergeData(array, left, mid, right,tmp);
		  
		  memcpy(array+left, tmp+left, sizeof(int)*(right - left));
	 }
}

为了方便调用,所以对其封装:

void MergeSort(int* array, int size)
{
	 int* tmp = (int*)malloc(sizeof(int)*size);
 
	 if (tmp == NULL)
	 {
		  assert(0);
	 }
 
	 _MergeSort(array, 0, size, tmp);
	 
	 free(tmp);
	 tmp = NULL;
}

循环写法:

<1>循环的跳出条件是gap<size,就是一组可以表示所有数据
<2>right和mid的取值可能越界,需要单独处理
<3>不需要分组,因为开始默认为单独存在,只需要把有序的元素整合为一组

void MergeSortNor(int* array, int size)
{
	 int* tmp = (int*)malloc(sizeof(int)*size);
 
	 if (tmp == NULL)
	 {
		  assert(0);
	 }
 
	 int gap = 1;
 
	 while (gap < size)
	 {
		  for (int i = 0; i < size; i += 2 * gap)
		  {
			   int left = i;
			   int mid = left + gap;
			   int right = mid + gap;
			   
			   if (right >= size)
			   {
				    right = size;
			   }
			   
			   if (mid >= size)
			   {
				    mid = size;
			   }
			   
			   MergeData(array, left, mid, right, tmp);
		  }
		  
		  memcpy(array, tmp, sizeof(int)*size);
		  gap *= 2;
	 }
	 
	 free(tmp);
	 tmp = NULL;
}

代码测试运行图:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值