详谈排序算法之交换类排序(两种方法实现快速排序【思路一致】)

1.冒泡排序

   起泡排序的思想非常简单。首先,将 n 个元素中的第一个和第二个进行比较,如果两个元素的位置为逆序,则交换两个元素的位置;进而比较第二个和第三个元素关键字,如此类推,直到比较第 n-1 个元素和第 n 个元素为止;上述过程描述了起泡排序的第一趟排序过程,在第一趟排序过程中,我们将关键字最大的元素通过交换操作放到了具有 n 个元素的序列的最一个位置上。然后进行第二趟排序,在第二趟排序过程中对元素序列的前 n-1 个元素进行相同操作,其结果是将关键字次大的元素通过交换放到第 n-1 个位置上。一般来说,第 i 趟排序是对元素序列的前 n-i+1 个元素进行排序,使得前 n-i+1 个元素中关键字最大的元素被放置到第 n-i+1 个位置上。排序共进行 n-1 趟,即可使得元素序列按关键字有序。

public void Bubble_Sort(int A[], int N) {
		for (int P = N - 1; P >= 0; P--) {
			int flag = 0;
			for (int i = 0; i < P; i++) {
				if (A[i] > A[i + 1]) {
					int temp = A[i];
					A[i] = A[i + 1];
					A[i + 1] = temp;
					flag = 1;
				}
			}
			if (flag == 0)
				break;
		}
		for (int i = 0; i < N; i++) {
			System.out.print(A[i] + " ");
		}
	}

【效率分析】

空间效率: 仅使用一个辅存单元。

时间效率: 假设待排序的元素个数为 n,则总共要进行 n-1 趟排序,对 j 个元素的子序列进行一趟起泡排序需要进行 j-1 次关键字比较。由此,起泡排序的总比较次数为

因此,起泡排序的时间复杂度为Ο(n~2)。

2.快速排序

   它的魅力之处在于它能在每次partition(排序算法的核心所在)都能为一个数组元素确定其排序最终正确位置(一次就定位准,下次循环就不考虑这个元素了)。

   快速排序是将分治法运用到排序问题中的一个典型例子,快速排序的基本思想是:通过一个枢轴(pivot)元素将
n 个元素的序列分为左、右两个子序列 Ll 和 Lr,其中子序列 Ll中的元素均比枢轴元素小,而子序列 Lr 中的元素均比枢轴元素大,然后对左、右子序列分别进行快速排序,在将左、右子序列排好序后,则整个序列有序,而对左右子序列的排序过程直到子序列中只包含一个元素时结束,此时左、右子序列由于只包含一个元素则自然有序。

 
用分治法的三个步骤来描述快速排序的过程如下:

划分步骤:通过枢轴元素 x 将序列一分为二, 且左子序列的元素均小于 x,右子序列的元素均大于 x;

治理步骤:递归的对左、右子序列排序;

组合步骤:无

从快速排序算法的描述中我们看到,快速排序算法的实现依赖于按照枢轴元素x对待排序序列进行划分的过程。

public static void Quick_Sort(int[] A, int begin, int end) {
		if (begin < end) {
			// 枢轴选定后永远不变,最终在中间,前小后大
			int key = A[begin];
			int i = begin;
			int j = end;
			// 大的元素放在右边,小的元素放在左边,来实现子集划分。
			while (i < j) { // 两端交替向内部扫描。
				while (i < j && A[j] > key) { // 当右侧元素大于枢轴元素,符合条件则指针左移。
					j--;
				}
				if (i < j) { // 当满足上面条件时,将两个元素倒换位置,并使指针从开始位置右移。
					A[i] = A[j];
					i++;
				}
				while (i < j && A[i] < key) { // 当右侧元素大于枢轴元素,符合条件则指针右移。
					i++;
				}
				if (i < j) {
					A[j] = A[i];
					j--;
				}
			}
			A[i] = key;
			System.out.println(i);
			Quick_Sort(A, begin, i - 1);
			Quick_Sort(A, i + 1, end);
		}
	}

	public static void quickSort(int[] n, int left, int right) {
		int pivot;
		if (left < right) {
			// pivot作为枢轴,较之小的元素在左,较之大的元素在右
			pivot = partition(n, left, right);
			// 对左右数组递归调用快速排序,直到顺序完全正确
			quickSort(n, left, pivot - 1);
			quickSort(n, pivot + 1, right);
		}
	}

	public static int partition(int[] n, int left, int right) {
		int pivotkey = n[left];
		// 枢轴选定后永远不变,最终在中间,前小后大
		while (left < right) {
			while (left < right && n[right] >= pivotkey)
				--right;
			// 将比枢轴小的元素移到低端,此时right位相当于空,等待低位比pivotkey大的数补上
			n[left] = n[right];
			while (left < right && n[left] <= pivotkey)
				++left;
			// 将比枢轴大的元素移到高端,此时left位相当于空,等待高位比pivotkey小的数补上
			n[right] = n[left];
		}
		// 当left == right,完成一趟快速排序,此时left位相当于空,等待pivotkey补上
		n[left] = pivotkey;
		return left;
	}

时间效率:快速排序算法的运行时间依赖于划分是否平衡,即根据枢轴元素 pivot 将序列划分为两个子序列中的元素个数,而划分是否平衡又依赖于所使用的枢轴元素。

   在平均情况下,经验证明,在所有同数量级的排序方法中,快速排序的常数因子
k 是最小的。因此就平均时间而言,快速排序被认为是目前最好的一种内部排序方法。

快速排序的平均性能最好,但是,若待排序序列初始时已按关键字有序或基本有序,则快速排序蜕化为起泡排序,其时间复杂度为Ο(n2)。为改进之,可以采取随机选择枢轴元素pivot的方法,具体做法是,在待划分的序列中随机选择一个元素然后与r[low]交换,再将r[low]作为枢轴元素,作如此改进之后将极大改进快速排序在序列有序或基本有序时的性能,在待排序元素个数n较大时,其运行过程中出现最坏情况的可能性可以认为不存在。

空间效率:虽然从时间上看快速排序的效率优于前述算法,然而从空间上看,在前面讨论的算法中都只需要一个辅助空间,而快速排序需要一个堆栈来实现递归。若每次划分都将序列均匀分割为长度相近的两个子序列,则堆栈的最大深度为 log
n,但是,在最坏的情况下,堆栈的最大深度为 n。

时间: 2024-10-22 13:37:36

详谈排序算法之交换类排序(两种方法实现快速排序【思路一致】)的相关文章

排序算法总结----比较类排序

概述:排序算法可分为比较性的排序,以及运算性的排序:这里详细介绍这些排序的原理,性能,实现,以及应用场合. 前面是维基百科的介绍,这里介绍几个比较典型的算法. 理论 计算复杂性理论 大O符号 全序关系 列表 稳定性 比较排序 自适应排序 排序网络 整数排序 交换排序 冒泡排序 鸡尾酒排序 奇偶排序 梳排序 侏儒排序 快速排序 臭皮匠排序 Bogo排序 选择排序 选择排序 堆排序 Smooth排序 笛卡尔树排序 锦标赛排序 循环排序 插入排序 插入排序 希尔排序 二叉查找树排序 图书馆排序 Pat

排序算法总结----运算类排序

运算排序 第一:计数排序 1:原理 对于每个输入数,确定小于该数的个数.这样可以直接把数放在输出数组的位置. 2:性能 最差时间复杂度 最优时间复杂度 平均时间复杂度 最差空间复杂度 注:稳定算法 3:应用 适合0~100的范围的数,当然可以和基排序结合而扩展数的范围. 4:实现 void CountingSort(int *A, int *B, int array_size, int k) { int i, value, pos; int * C=new int[k+1]; for(i=0;

Javascript使用function创建类的两种方法

1.使用function类 //myFunction.js var CMyFunc=function() { //类的公共方法,供外部调用 this.Func1=function() { var i=0; return i; } this.Func2=function() { _privateFunc(); } //类中的私有方法,供公共方法调用 function _privateFunc() { return 0; ] } CMyFunc myFunc=new CMyFunc(); 使用:其它

详谈排序算法之选择类排序(两种方法实现堆排序)

   今天我们再来讨论一下选择类排序,选择类排序分为:简单排序,树形选择排序和堆排序.但我们主要说的是简单和堆排序两个,因为树形选择排序使用了较多的辅助空间,以及和∞进行多余比较,为弥补树型选择排序的这些缺点, J.W.J.Williams 在 1964 年提出了进一步的改进方法,即堆排序.对于我个人而言..一开始并不是很理解它的算法思想,纠结了许久.在网上查找资料的时候发现这位大神的文章思路十分清晰,而且把创建堆以及堆化数组的算法讲解的十分详细.如果有不明白堆排序思路的,可以先看看这篇文章~堆

详谈排序算法之插入类排序(两种思路实现希尔排序)

1. 排序( sorting) 的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列.其确切的定义为: 假设有n个数据元素的序列{R1 , R2 , - , Rn},其相应关键字的序列是{K1 , K2 , - , Kn} ,通过排序要求找出下标 1 , 2 , - , n的一种排列p1 , p2 , - , pn,使得相应关键字满足如下的非递减(或非递增)关系Kp1 ≤ Kp2 ≤ - ≤ Kpn这样,就得到一个按关键字有序的纪录序列{ Rp1 , Rp2 , - , Rpn }

常见排序算法——七大比较类排序算法

算法 最坏复杂度 平均复杂度 最好复杂度 空间复杂度 选择排序 O($n^2$) O($n^2$) O($n^2$) O(1) 插入排序 O($n^2$) O($n^2$) O($n$) O(1) 希尔排序 O($nlog(n))$~O($n^2$) O($n^{1.3}$) O($n^2$) O(1) 冒泡排序 O($n^2$) O($n^2$) O(n)(用交换flag改进) O(1) 快速排序 O($n^2$) O($nlog(n)$) O($nlog(n)$) O(log(n))~O(n

http的get字符串类型和post自定义类的两种方法--测试成功

1. string类型的参数,get方法 /// <summary> /// 执行服务的方法 /// </summary> /// <param name="MethodName">方法名称</param> /// <param name="pars">参数列表</param> /// <param name="_type">返回值类型</param>

字符串反序列化成类的两种方法

ApiResult<AllowanceEntity> res = JsonConvert.DeserializeObject<ApiResult<AllowanceEntity>>(result.Value); str = JsonConvert.SerializeObject(obj); 还一个  javascript 里面  添加引用  system.web.extention

HTTPS的证书未经权威机构认证的情况下,访问HTTPS站点的两种方法

注意一下文章中提到的jsse在jdk1.4以后已经集成了,不必纠结. 摘 要 JSSE是一个SSL和TLS的纯Java实现,通过JSSE可以很容易地编程实现对HTTPS站点的访问.但是,如果该站点的证书未经权威机构的验证,JSSE将拒绝信任该证书从而不能访问HTTPS站点.本文在简要介绍JSSE的基础上提出了两种解决该问题的方法. 引言 过去的十几年,网络上已经积累了大量的Web应用.如今,无论是整合原有的Web应用系统,还是进行新的Web开发,都要求通过编程来访问某些Web页面.传统的方法是使