• 友链

  • 首页

  • 文章归档
h u a n b l o g
h u a n b l o g

欢

HI,Friend

04月
06
数据结构

交换排序

发表于 2022-04-06 • 字数统计 2836 • 被 1,234 人看爆

概述

基本思想:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换。直到没有反序的记录为止。应用交换排序基本思想的主要排序方法有。冒泡排序和快速排序。

冒泡排序

算法思想

通过相邻元素之间的比较和交换,使关键字较小的元素逐渐从底部移向顶部,关键字较大的元素逐渐下移(后移),小的上浮,大的下沉,所以冒泡排序又被称为"起泡"排序。

步骤

第一趟扫描。依次比较(R[n],R[n-1]),R[n-1],R[n-2]),...,(R[2],R[1]),对于每对气泡(R[j+1],R[j]),若R[j+1]< R[j],则交换R[j+1]和R[j]的内容。第一趟扫描完毕时,“最轻"的气泡就飘浮到该区间的顶部,即关键字最小的记录被放在最高位置R[1]上。然后再对R[n]~R[2]的记录进行第二趟排序,使次小关键字的元素被上浮到R[2]中,重复进行,n-1趟后,整个冒泡排序结束。

实例分析

有8个记录的关键字序列为(36,28,45,13,67,36,18,56),如下图所示为该序列起泡排序的全过程.
注意: 该方法是自后向前扫描的
冒泡排序实例分析.png

步骤如下:

该方法是采用自后向前扫描,一般用前向后扫描
第一轮:
① 18和56比较,18比56小,放在56前面,无需变动
② 18和36比较,18比36小,18与36交换位置
③ 18和67比较,18比67小,18与67交换位置
④ 18和13比较,18比13大,无需变动
⑤ 13和45交换,13比45小,交换位置
⑥ 13和28交换,13比28小,交换位置
⑦ 13和36交换,13比36小,交换位置
这样顺序为:13、36、28、45、18、67、36、56
其他几轮也是同样的方法,直到排序完成

算法描述

/*
* 冒泡排序
* 参数说明:
*		array -- 待排序的数组
*		n -- 数组长度
*/
void BubbleSort(int array[], int n)
{
	//采用自底向上扫描数组R[1.. n]做冒泡排序
	int i, j, temp;
	for (int i = 0; i < n - 1; i++) {
		// 每一趟的元素比较,注意 -1, 两个元素的数组推导一下就懂了。
		for (int j = 0; j < n - i - 1; j++) {
			cout << j << " ,";
			if (array[j] > array[j + 1]) {
				int temp = array[j];
				array[j] = array[j + 1];
				array[j + 1] = temp;
			}
		}
	}
}

算法分析

(1)算法的最好时间复杂度

若待排序记录为有序(最好情况),则一趟扫描完成,关键比较次数为n-1次且没有移动,比较的时间复杂度为O(n)

(2)算法的最坏时间复杂度

若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1<i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。总的比较次数为:(n-1)+(n-2)+ ... +1= n(n-1)/2,总的移动次数为3n(n-1)/2。在平均情况下,比较和移动记录的总次数大约为最坏情况下的一半,所以,冒泡排序算法的时间复杂度为O(n^2)。

(3)算法的空间复杂度

冒泡排序的空间复杂度为O(1),是就地排序

(4)算法稳定性

冒泡排序是稳定的。

冒泡排序排序过程视频

快速排序

算法思想

  基本思想:首先在当前无序区R[1ow...high]中任取一个记录作为排序比较的基准(不妨设为x),用此基准将当前无序区划分为两个较小的无序区R[low...i-1]和R[i+1...high],并使左边的无序区中所有记录的关键字均小于等于基准的关键字,右边的无序区中所有记录的关键字均大于等于基准的关键字,而基准记录x则位于最终排序的位置i上,这个过程称为一趟快速排序(或一次划分)。当R[lowr...i-1]和R[i+1...high]均非空时,分别对它们进行上述划分,直到所有的无序区中的记录均已排好序为止。
  一趟快速排序的具体操作是:设两个指针i和j,它们的初值分别为low和high,基准记录x=R[i],首先从j所指位置起向前搜索找到第一个关键字小于基准x.key的记录存入当前i所指向的位置上,i自增1,然后再从i所指位置起向后搜索,找到第一个关键字大于x .key的记录存入当前;所指向的位置上,j自减1:重复这两步,直至i等于j为止。

简述

  • ①选定中心轴数值Pivot(一般选择第一个)
  • ②将大于Pivot的数字放在Pivot的右边
  • ③将小于Pivot的数字放在Pivot的左边
  • ④分别重复上述步骤,直至排序完成

实例分析

排序过程:
快速排序实例分析.png
快速排序实例分析2.png

详细步骤

选择一个Pivot值45(排序后,左边的值比他小,右边的值比他大)
设置两个指针,分别放置在头部和尾部
比较左边指针是否小于Pivot,是的话放置在左边,否则不动,指针右移
比较右边指针是否大于Pivot,是的话放置在右边,否则不动,指针左移
直到左右指针重合
第一轮:

  • ①由于默认45是Pivot,所以45所在的下标,为空,无需比较,比较尾部指针32比45小,放置在45的位置上,左侧指针有数据了,右移(下标为53),右侧指针由于刚才取走数据为空,保持不变,排序过程第二行
  • ②查看左右两指针哪个不为空,进行比较(一般都不为空的话,则从左到右),左指针当前所在为53,与Pivot进行比较,发现比Pivot大,将53放置到右指针所指向下标上,并将有指针左移一位(移动到36下),排序过程第三行
  • ③查看左右两指针哪个不为空,进行比较,发现左指针为空,右指针指向36,将36与Pivot进行比较,发现比Pivot(45)小,放置到左指针指向的下标(右指针为空),左指针右移(到18下),排序过程第四行
  • ④查看左右两指针哪个不为空,进行比较,发现右指针为空,左指针指向18,将18与Pivot进行比较,发现比Pivot(45)小,不移动元素,将左指针向右移动一位(指向49),将其与Pivot进行比较,比Pivot大,将其放置到右指针指向的下标上,右指针左移(指向97),排序过程第五行、第六行
  • ⑤查看左右两指针哪个不为空,进行比较,发现左指针为空,右指针指向97,与Pivot进行比较,比Pivot大,元素不移动,右指针左移(指向13),排序过程第七行
    。。。。
    按上面步骤进行比较,直到左右指针重合,该下标即为Pivot放置的位置,即可看到Pivot左边的比他小,右边的比他大,如排序过程最后一行

继续重复第一轮操作,直到排序完成

算法描述

/*
 * 快速排序
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     l -- 数组的左边界(例如,从起始位置开始排序,则l=0)
 *     r -- 数组的右边界(例如,排序截至到数组末尾,则r=a.length-1)
 */
void QuickSort(int a[], int l, int r)
{
	if (l < r)
	{
		int i, j, x;
		i = l;
		j = r;
		x = a[i];
		while (i < j)
		{
			while (i < j && a[j] > x)
				j--; // 从右向左找第一个小于x的数
			if (i < j)
				a[i++] = a[j];
			while (i < j && a[i] < x)
				i++; // 从左向右找第一个大于x的数
			if (i < j)
				a[j--] = a[i];
		}
		a[i] = x;
		QuickSort(a, l, i - 1); /* 递归调用 */
		QuickSort(a, i + 1, r); /* 递归调用 */
	}

}

算法分析

(1)算法时间复杂度

快速排序的时间复杂度为O(nlogn)。快速排序方法被认为是排序时间效率非常高的一种方法,但是,当参加排序的原始序列已经是一个按值有序或基本有序的序列时,快速排序方法的时间效率将降到最低,这种情况下其时间复杂度为o(n^2)

(2)算法空间复杂度

快速排序的空间复杂度为O(log2n)。

(3)算法的稳定性

快速排序方法是一种不稳定的排序方法。

快速排序排序过程

参考

skywang12345-快速排序

分享到:
选择排序
插入排序
  • 文章目录
  • 站点概览
欢

网红 欢

你能抓到我么?

Email RSS
看爆 Top5
  • mac系统版本与Xcode版本有冲突 4,091次看爆
  • JAVA_HOME环境配置问题 3,741次看爆
  • AssetBundle使用 3,510次看爆
  • VSCode配置C++开发环境 3,264次看爆
  • Lua反射 3,141次看爆

Copyright © 2025 欢 粤ICP备2020105803号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图