【算法导论 第7章 快速排序】

一、快速排序算法的基本特性
时间复杂度:O(n*lgn)
最坏:O(n^2)
空间复杂度:O(n*lgn)
不稳定。

快速排序是一种排序算法,对包含n个数的输入数组,平均时间为O(nlgn),最坏情况是O(n^2)。
通常是用于排序的最佳选择。因为,排序最快,也只能达到O(nlgn)。


二、快速排序算法的描述
算法导论,第7章
快速排序时基于分治模式处理的,
对一个典型子数组A[p...r]排序的分治过程为三个步骤:
1.分解:
A[p..r]被划分为俩个(可能空)的子数组A[p ..q-1]和A[q+1 ..r],使得
A[p ..q-1] <= A[q] <= A[q+1 ..r]
2.解决:通过递归调用快速排序,对子数组A[p ..q-1]和A[q+1 ..r]排序。
3.合并。

 

三、快速排序算法

          快速排序算法的关键是PARTITION过程,它对A[p..r]进行就地重排:

PARTITION(A, p, r)
1  x ← A[r]         //以最后一个元素,A[r]为主元
2  i ← p - 1
3  for j ← p to r - 1    //注,j从p指向的是r-1,不是r。
4       do if A[j] ≤ x
5             then i ← i + 1
6                  exchange A[i] <-> A[j]
7  exchange A[i + 1] <-> A[r]    //最后,交换主元
8  return i + 1

然后,对整个数组进行递归排序:

QUICKSORT(A, p, r)
1 if p < r
2    then q ← PARTITION(A, p, r)   //关键
3         QUICKSORT(A, p, q - 1)
4         QUICKSORT(A, q + 1, r)

          四、代码

#include <stdio.h>

void swap(int *a, int *b);
void print(int* data, int len);

int partition(int* data, int lo, int hi)
{
	int i = lo - 1;
	int j = lo;

	int key = data[hi];

	for (; j < hi; j++) // 住:j < hi ,不是 j <= hi
	{
		if (data[j] <= key)
		{
			i += 1;
			swap(&data[i], &data[j]);
		}
	}

	swap(&data[i+1], &data[hi]);

	return i + 1;
}

void quicksort(int data[], int lo, int hi)
{
	if (lo < hi)
	{
		int q = partition(data, lo, hi);

		quicksort(data, lo, q-1);
		quicksort(data, q+1, hi);
	}
	return;
}


void main()
{
	int arr[] = {5, 4, 8, 9, 1, 3, 2, 6, 7, 10, 6};

	print(arr, 11);

	quicksort(arr, 0, 10);

	print(arr, 11);
}


void swap(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

void print(int* data, int len)
{	
	for (int i = 0; i < len; i++)
	{
		printf("%4d",data[i]);
	}
	printf("\n");
}

五、拓展

问题描述:
我们将乱序的红白蓝三色小球排列成有序的红白蓝三色的同颜色在一起的小球组。这个问题之所以叫荷兰国旗,是因为我们可以将红白蓝三色小球想象成条状物,有序排列后正好组成荷兰国旗。如下图所示:

    

    这个问题,类似快排中partition过程。不过,要用三个指针,一前begin,一中current,一后end,俩俩交换。

1、current遍历,整个数组序列,current++,
2、current指0,与begin交换,而后current++,begin++,
3、current指2,与end交换,而后,current不动,end--。

    为什么,第三步,current指2,与end交换之后,current不动了列,对的,正如algorithm__所说:current之所以与begin交换后,current++、begin++,是因为此无后顾之忧。而current与end交换后,current不动,end--,是因有后顾之忧。

    为什么啊,因为你想想啊,你最终的目的无非就是为了让0、1、2有序排列,试想,如果第三步,current与end交换之前,万一end之前指的是0,而current交换之后,current此刻指的是0了,此时,current能动么?不能动啊,指的是0,还得与begin交换列。

    ok,说这么多,你可能不甚明了,直接引用下gnuhpc的图,就一目了然了:

    
    

    本程序代码:

#include <stdio.h>

void swap(int *a, int *b);
void print(int* data, int len);


void main()
{
	int arr[] = {0, 1, 2, 1, 1, 2, 0, 2, 1, 0};

	/* 初始化 begin, current, end */
	int *begin = arr;
	int *current = arr;
	int *end = arr + 9;
	
	/* 排序前,打印数组 */
	print(arr, 10);

	/* current 遍历整个数组 */
	while (current <= end)
	{
		/* current指0,与begin交换,而后current++,begin++ */
		if (0 == *current)
		{
			swap(begin, current);
			begin++;
			current++;
		}
		/* current指向1,current ++ */
		else if (1 == * current)
		{
			current++;
		}
		/* current指2,与end交换,而后,current不动,end-- */
		else
		{
			swap(end, current);
			end--;
		}
	}
	/* 排序后,打印数组 */
	print(arr, 10);

}


void swap(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

void print(int* data, int len)
{	
	for (int i = 0; i < len; i++)
	{
		printf("%4d",data[i]);
	}
	printf("\n");
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值