c语言快速排序 (递归与非递归实现)

数据结构 专栏收录该内容
14 篇文章 0 订阅

递归

1、先在待排序序列中选择一个基准数据,一般常用的就是第一个数据
2、i,j : i从前向后 j从后向前 当i < j时,进入循环
(1)从后向前找第一个比基准小的数据(i<j),找到后就将其放到i位置
(2)从前向后找第一个比基准大的数据(i<j),找到后就将其放到j位置
3、将基准的值存储到i位置
4、基准将数据序列划分成左右两部分,当左右两部分的数据量大于1时,递归处理左右两部分。

// 在start位置 end位置 和中间位置找到中位数,将其换到start位置
void GetModNum(int *arr, int start, int end)
{
 	int mod = (end - start + 1) / 2 + start;
 	if (arr[mod] > arr[end])
 	{
  	Swap(&arr[mod], &arr[end]);
 	}
 	if (arr[start] > arr[end])
 	{
 		Swap(&arr[start], &arr[end]);
 	}
 	if (arr[start] > arr[mod])
 	{
  		Swap(&arr[start], &arr[mod]);
 	}
}

int Quick(int *arr, int start, int end)
{
 	//GetModNum(arr, start, end);
 	int tmp = arr[start];
 	while (start < end)  // 大循环,将待排序序列全部访问一遍
 	{
  		//小循环, 从后向前找第一个比基准小的数据,存储到start位置
  		while (start < end)
  		{
   			if (arr[end] < tmp) break;
   			end--;
  		}	
  		arr[start] = arr[end];
  		//小循环, 从前向后找第一个比基准大的数据,存储到end位置
  		while (start < end)
  		{
   			if (arr[start] > tmp) break;
   			start++;
  		}
  		arr[end] = arr[start];
 	}
 	arr[start] = tmp;
 	return start;
}

// arr是整个序列的起始地址,start是本次快排处理的数据的起始位置,end是本次快排处理的数据的结束位置
void OneQuick(int *arr, int start, int end)
{
 	int mod = Quick(arr, start, end);
 	if (mod - start > 1) // 判断其mod的左边超过1个数据,则进入递归处理mod的左边
 	{
  		OneQuick(arr, start, mod - 1);
 	}
 	if (end - mod > 1)
 	{
  		OneQuick(arr, mod + 1, end);
 	}
}

void QuickSort(int *arr, int len)
{
 	OneQuick(arr, 0, len - 1);
}

非递归

  非递归实现快速排序 – 栈 或 队列 -> 存储数据序列的起始位置和结束位置这一对数据
1、初始化栈或者队列 , 初始化空间的大小为O(logn) * 2 * sizeof(int)
2、将初始的起始位置(0)和结束位置(len-1)入栈或者入队列
3、循环 退出条件是:栈为空或者队列为空
(1) 出栈或者出队列,获取到本次要处理的序列的起始位置和结束位置
(2)执行一次快排操作,得到到mod位置
(3)判断mod的右边是否还有超过1个的数据, 如果有,将右边的起始位置和结束位置入栈或者入队列
(4)判断mod的左边是否还有超过1个的数据, 如果有,将左边的起始位置和结束位置入栈或者入队列
*/


typedef struct Peer
{
 	unsigned int start;
 	unsigned int end;
}Peer;
typedef struct Stack
{
 	Peer *data;
 	int   top;
}Stack;
void QuickSortNoR(int *arr, int len)
{
 	int size = (int)(log((double)len) / log((double)2)) + 1;
 	Stack st;
 	st.data = (Peer *)malloc(sizeof(Peer) * size);
 	assert(st.data != NULL);
 	st.top = 0;

 	Peer peer;
 	peer.start = 0;
 	peer.end = len - 1;
 	st.data[st.top++] = peer;

 	while (st.top != 0)
 	{
  		peer = st.data[--st.top];
  		int mod = Quick(arr, peer.start, peer.end);

  		if (peer.end - mod > 1)
  		{
   			Peer new_peer = { mod + 1, peer.end };
   			st.data[st.top++] = new_peer;
  		}
  		if (mod - peer.start > 1)
  		{
   			Peer new_peer = { peer.start, mod - 1 };
   			st.data[st.top++] = new_peer;
  		}
 	}

 	free(st.data);
}

快排的优化:

1、对选择基准的方式的优化: 随机选择 三位(第一位,最后一位,中间一位)取中(中位数)
2、数据量越小,数据越有序,直接插入排序的效率越高 当快排的数据量小于一定值后,直接用直接插入排序
3、对重复数据: 每次划分将与key相等的元素集中到key的周围,处理左边或右边时,这些数据不再参与
4、多线程并行处理

  • 4
    点赞
  • 4
    评论
  • 10
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值