冒 泡 排 序 详 细 解 析
- 格式:pdf
- 大小:179.70 KB
- 文档页数:10
冒泡排序的原理for循环冒泡排序的原理for循环 1原理:比较两个相邻的元素,将值大的元素交换至右端。
思路:依次比较相邻的两个数,将小数放在前面,大数放在后面。
即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。
然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。
重复第一趟步骤,直至全部排序完成。
第一趟比较完成后,最后一个数一定是数组中最大的一个数,所以第二趟比较的时候最后一个数不参与比较;第二趟比较完成后,倒数第二个数也一定是数组中第二大的数,所以第三趟比较的时候最后两个数不参与比较;依次类推,每一趟比较次数-1;……举例说明:要排序数组:int[] arr={6,3,8,2,9,1};第一趟排序:第一次排序:6和3比较,6大于3,交换位置: 3 6 8 2 9 1第二次排序:6和8比较,6小于8,不交换位置:3 6 8 2 9 1第三次排序:8和2比较,8大于2,交换位置: 3 6 2 8 9 11第五次排序:9和1比较:9大于1,交换位置: 3 6 2 8 1 9总共进行了5次比较,排序结果: 3 6 2 8 1 9第二趟排序:第一次排序:3和6比较,3小于6,不交换位置:3 6 2 8 1 9第二次排序:6和2比较,6大于2,交换位置: 3 2 6 8 1 9第三次排序:6和8比较,6大于8,不交换位置:3 2 6 8 1 9第四次排序:8和1比较,8大于1,交换位置: 3 2 6 1 8 9总共进行了4次比较,排序结果: 3 2 6 1 8 9第三趟排序:第一次排序:3和2比较,3大于2,交换位置: 2 3 6 1 8 9第二次排序:3和6比较,3小于6,不交换位置:2 3 6 1 8 99总共进行了3次比较,排序结果: 2 3 1 6 8 9第四趟排序:第一次排序:2和3比较,2小于3,不交换位置:2 3 1 6 8 9第二次排序:3和1比较,3大于1,交换位置: 2 1 3 6 8 9总共进行了2次比较,排序结果: 2 1 3 6 8 9第五趟排序:第一次排序:2和1比较,2大于1,交换位置: 1 2 3 6 8 9总共进行了1次比较,排序结果: 1 2 3 6 8 9最终结果:1 2 3 6 8 96 个数。
冒泡排序法教案第一篇:冒泡排序法教案数据结构——冒泡排序(第19讲,第9章)一、复习回顾什么是排序:排序是把一个无序的数据元素序列整理成有规律的按排序关键字递增(或递减)排列的有序序列的过程。
/************************************************(已经学过的排序方法有:直接插入排序、希尔排序、直接插入排序:顺序的把待排序序列中的各个记录按其关键字的大小,插入到已排序的序列的适当位置。
希尔排序:(缩小增量排序),不断把待排序的记录分成若干个小组,对同一组内的记录进行排序,在分组时,始终保持当前组内的记录个数超过前面分组排序时组内的记录个数。
)************************************************/二、第一小节(目标:理解掌握冒泡思想)1、给出冒泡排序的定义(25分钟)将待排序序列中第一个记录的关键字R1.key与第二个记录的关键字R2.key作比较,如果R1.key>R2.key,则交换记录R1和R2在序列中的位置,否则不交换;然后继续对当前序列中的第二个记录和第三个记录作同样的处理,依此类推,知道序列中倒数第二个记录和最后一个记录处理完为止,我们称这样的过程为一次冒泡排序。
2、请学生上台做排序练习(15分钟做题+10分钟讲解)(巩固排序思想的掌握)第一题: 38 5 19 26 49 97 1 66 第一次排序结果:5 19 26 38 49 1 66 [97] 第二次排序结果:5 19 26 38 1 49 [66 97] 第三次排序结果:5 19 26 1 38 [49 66 97] 第四次排序结果:5 19 1 26 [38 49 66 97] 第五次排序结果:5 1 19 [26 38 49 66 97] 第六次排序结果:1 5 [19 26 38 49 66 97] 第七次排序结果:1 [5 19 26 38 49 66 97] 最后结果序列: 1 5 19 26 38 49 66 97第二题: 8 7 6 5 4 3 2 1数据结构——冒泡排序(第19讲,第9章)答第一次排序: 7 6 5 4 3 2 1 [8] 第二次排序: 6 5 4 3 2 1 [7 8] 第三次排序: 5 4 3 2 1 [6 7 8] 第四次排序: 4 3 2 1 [5 6 7 8] 第五次排序: 3 2 1 [4 5 6 7 8] 第六次排序: 2 1 [3 4 5 6 7 8] 第七次排序:1 [2 3 4 5 6 7 8] 最后结果序列: 1 2 3 4 5 6 7 8第二题: 1 2 3 4 5 6 7 8 第一次排序: 1 2 3 4 5 6 7 [8] 第二次排序: 1 2 3 4 5 6 [7 8] 第三次排序: 1 2 3 4 5 [6 7 8] 第四次排序:1 2 3 4 [5 6 7 8] 第五次排序: 1 2 3 [4 5 6 7 8] 第六次排序: 1 2 [3 4 5 6 7 8] 第七次排序: 1 [2 3 4 5 6 7 8] 最后结果序列: 1 2 3 4 5 6 7 8]从练习题中引出:一次冒泡排序的结果:使关键字最大的记录排在了序列的最后一个位置上。
一、实验目的1. 理解冒泡排序算法的基本原理和实现过程。
2. 分析冒泡排序算法的时间复杂度和空间复杂度。
3. 通过实验验证冒泡排序算法在不同数据规模下的性能表现。
二、实验环境1. 操作系统:Windows 102. 编程语言:Python3.73. 开发环境:PyCharm三、实验内容1. 冒泡排序算法的实现2. 冒泡排序算法的性能测试3. 结果分析四、实验步骤1. 实现冒泡排序算法```pythondef bubble_sort(arr):n = len(arr)for i in range(n):for j in range(0, n-i-1):if arr[j] > arr[j+1]:arr[j], arr[j+1] = arr[j+1], arr[j]return arr```2. 生成测试数据```pythonimport randomdef generate_data(n):return [random.randint(0, 10000) for _ in range(n)]```3. 测试冒泡排序算法性能```pythondef test_bubble_sort():data_sizes = [100, 1000, 10000, 100000]for size in data_sizes:data = generate_data(size)sorted_data = bubble_sort(data.copy())assert sorted_data == sorted(data), "排序结果错误"print(f"数据规模:{size}, 排序耗时:{time.time() - start_time:.4f}秒")start_time = time.time()test_bubble_sort()print(f"实验总耗时:{time.time() - start_time:.4f}秒")```五、结果分析1. 冒泡排序算法的时间复杂度分析冒泡排序算法的时间复杂度主要取决于两层循环的执行次数。
冒泡排序,是指计算机的一种排序方法,它的时间复杂度为O(n^2),虽然不及堆排序、快速排序的O(nlogn,底数为2),但是有两个优点:1.“编程复杂度”很低,很容易写出代码;2.具有稳定性,这里的稳定性是指原序列中相同元素的相对顺序仍然保持到排序后的序列,而堆排序、快速排序均不具有稳定性。
不过,一路、二路归并排序、不平衡二叉树排序的速度均比冒泡排序快,且具有稳定性,但速度不及堆排序、快速排序。
冒泡排序是经过n-1趟子排序完成的,第i趟子排序从第1个数至第n-i个数,若第i个数比后一个数大(则升序,小则降序)则交换两数冒泡排序(BubbleSort)的基本概念是:依次比较相邻的两个数,将小数放在前面,大数放在后面。
即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。
然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。
至此第一趟结束,将最大的数放到了最后。
在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。
如此下去,重复以上过程,直至最终完成排序。
由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
用二重循环实现,外循环变量设为i,内循环变量设为j。
外循环重复9次,内循环依次重复9,8,...,1次。
每次进行比较的两个元素都是与内循环j有关的,它们可以分别用a[j]和a[j+1]标识,i的值依次为1,2,...,9,对于每一个i,j的值依次为1,2,...10-i。
产生在许多程序设计中,我们需要将一个数列进行排序,以方便统计,而冒泡排序一直由于其简洁的思想方法而倍受青睐。
排序过程设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。
冒泡排序法算法分析冒泡排序算法的运作如下:1.⽐较相邻的元素。
如果第⼀个⽐第⼆个⼤,就交换他们两个。
2.对每⼀对相邻元素作同样的⼯作,从开始第⼀对到结尾的最后⼀对。
这步做完后,最后的元素会是最⼤的数。
3.针对所有的元素重复以上的步骤,除了最后⼀个。
4.持续每次对越来越少的元素重复上⾯的步骤,直到没有任何⼀对数字需要⽐较。
具体如何进⾏移动呢?让我们来看⼀个例⼦:有8个数组成上⾯⼀个⽆序数列:5,8,6,5,9,2,1,7,⽬标是从⼩到⼤排序。
按照冒泡排序的思想,过程如下:⾸先让5和8⽐较,8⽐5⼤,故两者不进⾏交换。
接下来8和6⽐较,8⽐6⼤,两者进⾏交换。
继续8和3⽐较,交换8和3的位置。
继续8和9⽐较,9⽐8⼤,两者不进⾏交换。
然后⽐较9和2,9⽐2⼤,两者进⾏交换。
接下来⽐较9和1,9⽐1⼤,两者进⾏交换。
在最后⽐较9和7,9⼤于7,两者进⾏交换。
经过上⾯的冒泡排序的第⼀轮运作。
数列最右侧元素可以认为是⼀个有序区域,有序区域⽬前只有⼀个元素。
接下来进⾏如上的7轮排序得到最终的有序数列:第六轮、第七轮、第⼋轮排序:第六轮排序:第七轮排序:第⼋轮排序:问题分析:在6-8轮中我们待排序的数列早就已经是有序的数列的,可是冒泡排序依旧进⾏⽐较。
算法改进1:在进⾏每⼀轮的排序⼯作时判断数列是否有序,如已经是有序的数列则将排序⼯作提早结束。
算法改进2:算法改进的关键点在于对数列有序区的界定。
按照冒泡排序的逻辑,有序区的长度和排序的轮数是相等的。
⽐如第⼀轮排序过后的有序长度为1,第⼆轮排序后有序长度是2……但是实际情况是这样⼦的吗?实际上,数列真正的有序区可能会⼤于这个长度。
那么后⾯的许多元素的⽐较是没有意义的。
解决思路:在每⼀轮排序的最后,记录下最后⼀个元素交换的位置,那个位置也就是⽆序数列的边界,再往后就是有序区了。
基本的冒泡排序代码://冒泡排序函数版本1private static void SortBubbling(int[] arr_Native) {int temp;for (int i = 0; i < arr_Native.length-1; i++) { //外循环只需要⽐较arr.length-1次就可以for (int j = 0; j < arr_Native.length-i-1; j++) { //内循环需要⽐较arr_Native.length-i-1if (arr_Native[j]>arr_Native[j+1]) {temp=arr_Native[j];arr_Native[j]=arr_Native[j+1];arr_Native[j+1]=temp;}}}}算法改进1后的代码://冒泡排序函数版本2//利⽤boolean变量isSored作为标记。
第1篇一、实验目的1. 理解冒泡排序算法的基本原理和操作步骤。
2. 掌握冒泡排序算法的实现方法。
3. 分析冒泡排序算法的时间复杂度和空间复杂度。
4. 通过实验验证冒泡排序算法的效率。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发环境:Visual Studio 2019三、实验原理冒泡排序是一种简单的排序算法,其基本思想是通过多次比较和交换相邻元素,将待排序的序列变为有序序列。
冒泡排序算法的基本步骤如下:1. 从第一个元素开始,相邻的两个元素进行比较,如果它们的顺序错误(即第一个元素大于第二个元素),则交换它们的位置。
2. 重复步骤1,对相邻的元素进行比较和交换,直到整个序列的最后一个元素。
3. 第一轮排序完成后,最大的元素被放置在序列的最后一个位置。
4. 从第一个元素开始,对剩余的元素重复步骤1和步骤2,直到序列的倒数第二个元素。
5. 重复步骤3和步骤4,直到整个序列有序。
四、实验步骤1. 编写冒泡排序算法的C++代码,实现上述算法步骤。
2. 在主函数中创建一个待排序的数组。
3. 调用冒泡排序函数对数组进行排序。
4. 输出排序前后的数组,验证排序结果。
五、实验代码```cppinclude <iostream>using namespace std;// 冒泡排序函数void bubbleSort(int arr[], int n) {for (int i = 0; i < n - 1; i++) {for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) {// 交换相邻元素int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}// 打印数组函数void printArray(int arr[], int n) {for (int i = 0; i < n; i++) {cout << arr[i] << " ";}cout << endl;}int main() {// 创建待排序的数组int arr[] = {64, 34, 25, 12, 22, 11, 90};int n = sizeof(arr) / sizeof(arr[0]);// 打印排序前的数组cout << "排序前的数组:\n";printArray(arr, n);// 调用冒泡排序函数bubbleSort(arr, n);// 打印排序后的数组cout << "排序后的数组:\n";printArray(arr, n);return 0;}```六、实验结果与分析1. 运行实验程序,输出排序前后的数组,验证排序结果是否正确。
冒泡排序实现代码以及图⽰详解⼀、冒泡排序冒泡排序(Bubble Sort),是⼀种计算机科学领域的较简单的排序算法。
它重复地⾛访过要排序的元素列,依次⽐较两个相邻的元素,如果顺序(如从⼤到⼩、⾸字母从Z到A)错误就把他们交换过来。
⾛访元素的⼯作是重复地进⾏直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越⼩的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中⼆氧化碳的⽓泡最终会上浮到顶端⼀样,故名“冒泡排序”。
⼆、算法实现原理1. ⽐较相邻的元素。
如果第⼀个⽐第⼆个⼤,就交换它们两个;2. 对每⼀对相邻元素作同样的⼯作,从开始第⼀对到结尾的最后⼀对,在这⼀点,最后的元素理应会是最⼤的数;3. 针对所有的元素重复以上的步骤,除了最后⼀个;4. 持续每次对越来越少的元素重复上⾯的步骤,直到没有任何⼀对数需要⽐较;三、复杂度分析若⽂件的初始状态是正序的,⼀趟扫描即可完成排序。
所需的关键字⽐较次数C和记录移动次数M均达到最⼩值:所以,冒泡排序最好的时间复杂度为:O(n)若初始⽂件是反序的,需要进⾏n-1趟排序。
每趟排序要进⾏n-i次关键字的⽐较(1≤i≤n-1),且每次⽐较都必须移动记录三次来达到交换记录位置。
在这种情况下,⽐较和移动次数均达到最⼤值:冒泡排序的最坏时间复杂度为O(n^2)所以,冒泡排序总的时间复杂度为O(n^2)四、稳定性分析冒泡排序就是把⼩的元素往前调或者把⼤的元素往后调。
⽐较是相邻的两个元素⽐较,交换也发⽣在这两个元素之间。
所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前⾯的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是⼀种稳定排序算法。
五、算法图⽰分析图⽰过程动图展⽰六、JAVA代码实现1//⽐较函数参考2static boolean less(Comparable v, Comparable w) {3return pareTo(w) < 0;4 }5//交换函数6static void exchange(Object[] a, int i, int j) {7 Object swap = a[i];8 a[i] = a[j];9 a[j] = swap;10 }1112public void bubblesort(Comparable[]a){13int n = a.length;14for(int i=0;i<n-1;i++){//记录已经排序的元素的数量15for(int j=0;j<n-i-1;j++){//开始排序,除去了已经排序了的16if(a[j]<a[j+1]){ //降序排列17 swap(a,j,j+1);18 }19 }20 }21 }七、算法优化针对问题:数据的顺序排好之后,冒泡算法仍然会继续进⾏下⼀轮的⽐较,直到arr.length-1次,后⾯的⽐较没有意义的。
冒泡排序算法冒泡排序是一种经典的排序算法,其思想是通过相邻元素之间的比较和交换来实现排序。
在排序的过程中,较大的元素不断地往后移动,类似于“冒泡”的过程,故称为冒泡排序。
冒泡排序算法的思想非常简单,可以用几行伪代码描述出来:1.从数组的第一个元素开始,依次比较相邻的两个元素,如果前一个元素比后一个元素大,则交换它们的位置。
2.继续对数组的下一个元素进行比较,重复以上操作,直到达到数组的末尾。
3.重复以上操作,直到整个数组排序完成,即没有需要交换的元素。
冒泡排序算法的时间复杂度为O(n^2),其中n表示需要排序的元素的个数。
在实际应用中,冒泡排序算法的效率较低,并不能满足大规模数据的排序需求。
然而,对于小规模的数据排序,冒泡排序算法仍然具有一定的优势。
此外,冒泡排序算法的实现过程简单容易理解,是学习排序算法的入门课程。
下面我们对冒泡排序算法进行详细的分析和讨论,并对其应用场景和改进方法进行探讨。
一、冒泡排序算法实现过程冒泡排序算法的实现过程非常简单,可以分为以下几个步骤:1.定义一个长度为n的数组a,用于存储需要排序的元素。
2.利用嵌套循环,对数组a进行遍历,外层循环控制排序的轮数,内层循环控制每轮比较的次数。
3.在每一轮比较中,依次比较相邻的两个元素。
如果前一个元素比后一个元素大,则交换它们的位置。
4.每一轮比较结束后,数组a中最大的元素被放在了数组a的最后一个位置。
5.重复以上步骤,直到整个数组a排序完成。
具体实现过程如下所示:```void bubble_sort(int a[], int n){ int i, j, temp;for(i=0; i<n-1; i++){for(j=0; j<n-i-1; j++){if(a[j]>a[j+1]){temp = a[j];a[j] = a[j+1];a[j+1] = temp;}}}}```上述代码定义了一个名为bubble_sort的函数,用于对一个整型数组a进行冒泡排序。
js实现冒泡排序,快速排序,堆排序【解析时间空间复杂度】文章目录冒泡排序(Bubble Sort)快速排序堆排序冒泡排序(Bubble Sort)时间复杂度最好的情况:数组本身是顺序的,外层循环遍历一次就完成O(n)最坏的情况:,O(n2)数组本身是逆序的,内外层遍历O(n2)空间复杂度开辟一个空间交换顺序O(1)稳定,因为if判断不成立,就不会交换顺序,不会交换相同元素冒泡排序它在所有排序算法中最简单。
然而,从运行时间的角度来看,冒泡排序是最差的一个,它的复杂度是O(n2)。
冒泡排序比较任何两个相邻的项,如果第一个比第二个大,则交换它们。
元素项向上移动至正确的顺序,就好像气泡升至表面一样,冒泡排序因此得名。
交换时,我们用一个中间值来存储某一交换项的值。
其他排序法也会用到这个方法,因此我们声明一个方法放置这段交换代码以便重用。
使用ES6(ECMAScript 2015)**增强的对象属性——对象数组的解构赋值语法,**这个函数可以写成下面这样:[array[index1], array[index2]] = [array[index2], array[index1]];具体实现:function bubbleSort(arr) {for (let i = 0; i arr.length; i++) {--外循环(行{2})会从数组的第一位迭代至最后一位,它控制了在数组中经过多少轮排序 for (let j = 0; j arr.length - i; j++) {--内循环将从第一位迭代至length - i位,因为后i位已经是排好序的,不用重新迭代 if (arr[j] arr[j + 1]) {--如果前一位大于后一位[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];--交换位置return arr;快速排序时间复杂度最好的情况:每一次base值都刚好平分整个数组,O(nlogn)最坏的情况:每一次base值都是数组中的最大-最小值,O(n2)空间复杂度快速排序是递归的,需要借助栈来保存每一层递归的调用信息,所以空间复杂度和递归树的深度一致最好的情况:每一次base值都刚好平分整个数组,递归树的深度O(logn)最坏的情况:每一次base值都是数组中的最大-最小值,递归树的深度O(n)快速排序是不稳定的,因为可能会交换相同的关键字。
快速排序是递归的,特殊情况:leftright,直接退出。
(1) 首先,从数组中选择中间一项作为主元base,一般取第一个值。
(2) 创建两个指针,左边一个指向数组第一个项,右边一个指向数组最后一个项。
移动右指针直到找到一个比主元小的元素,接着,移动左指针直到我们找到一个比主元大的元素,然后交换它们,重复这个过程,直到左指针遇见了右指针。
这个过程将使得比主元小的值都排在主元之前,而比主元大的值都排在主元之后。
这一步叫作划分操作。
(3)然后交换主元和指针停下来的位置的元素(等于说是把这个元素归位,这个元素左边的都比他小,右边的都比他大,这个位置就是他最终的位置)(4) 接着,算法对划分后的小数组(较主元小的值组成的子数组,以及较主元大的值组成的子数组)重复之前的两个步骤(递归方法),递归的出口为left-right=i,也就是:lefti-1 - i+1right此时,子数组数组已排序完成。
归位示意图:具体实现:function quicksort(arr, left, right) {if (left right) {var i = left,j = right,base = arr[left]; --基准总是取序列开头的元素-- var [base, i, j] = [arr[left], left, right]; --以left指针元素为basewhile (i != j) {--i=j,两个指针相遇时,一次排序完成,跳出循环-- 因为每次大循环里面的操作都会改变i和j的值,所以每次循环-操作前都要判断是否满足ijwhile (i j arr[j] = base) {--寻找小于base的右指针元素a,跳出循环,否则左移一位while (i j arr[i] = base) {--寻找大于base的左指针元素b,跳出循环,否则右移一位[arr[i], arr[j]] = [arr[j], arr[i]]; --交换a和b[arr[left], arr[j]] = [arr[j], arr[left]]; --交换相遇位置元素和base,base归位-- let k = i;quicksort(arr, left, i - 1); --对base左边的元素递归排序quicksort(arr, i + 1, right); --对base右边的元素递归排序 return arr;堆的概念堆是一个完全二叉树。
完全二叉树:二叉树除开最后一层,其他层结点数都达到最大,最后一层的所有结点都集中在左边(左边结点排列满的情况下,右边才能缺失结点)。
大顶堆:根结点为最大值,每个结点的值大于或等于其孩子结点的值。
小顶堆:根结点为最小值,每个结点的值小于或等于其孩子结点的值。
堆的存储:堆由数组来实现,相当于对二叉树做层序遍历。
如下图:时间复杂度总时间为建堆时间+n次调整堆—— O(n)+O(nlogn)=O(nlogn)建堆时间:从最后一个非叶子节点遍历到根节点,复杂度为O(n)n次调整堆:每一次调整堆最长的路径是从树的根节点到叶子结点,也就是树的高度logn,所以每一次调整时间复杂度是O(logn),一共是O(nlogn)空间复杂度堆排序只需要在交换元素的时候申请一个空间暂存元素,其他操作都是在原数组操作,空间复杂度为O(1)堆排序是不稳定的,因为可能会交换相同的子结点。
步骤一:建堆以升序遍历为例子,需要先将将初始二叉树转换成大顶堆,要求满足:树中任一非叶子结点大于其左右孩子。
实质上是调整数组元素的位置,不断比较,做交换操作。
找到第一个非叶子结点——Math.floor(arr.length - 2 - 1),从后往前依次遍历对每一个结点,检查结点和子结点的大小关系,调整成大根堆-- 建立大顶堆function buildHeap(arr) {--从最后一个非叶子节点开始,向前遍历,for (let i = Math.floor(arr.length - 2 - 1); i = 0; i--) { headAdjust(arr, i, arr.length); --对每一个节点都调整堆,使其满足大顶堆规则步骤二:调整指定结点形成大根堆建立childMax指针指向child最大值节点,初始值为2 * cur + 1,指向左节点当左节点存在时(左节点索引小于数组length),进入循环,递归调整所有节点位置,直到没有左节点为止(cur指向一个叶结点为止),跳出循环,遍历结束每次循环,先判断右节点存在时,右节点是否大于左节点,是则改变childMax的指向然后判断cur根节点是否大于childMax,大于的话,说明满足大顶堆规律,不需要再调整,跳出循环,结束遍历小于的话,说明不满足大顶堆规律,交换根节点和子结点,因为交换了节点位置,子结点可能会不满足大顶堆顺序,所以还要判断子结点然后,改变cur和childMax指向子结点,继续循环判断。
--从输入节点处调整堆function headAdjust(arr, cur, len) {let intialCur = arr[cur]; --存放最初始的let childMax = 2 * cur + 1; --指向子树中较大的位置,初始值为左子树的索引--子树存在(索引没超过数组长度)而且子树值大于根时,此时不符合大顶堆结构,进入循环,调整堆的结构while (childMax len) {--判断左右子树大小,如果右子树更大,而且右子树存在,childMax 指针指向右子树if (arr[childMax] arr[childMax + 1] childMax + 1 len) childMax++;--子树值小于根节点,不需要调整,退出循环if (arr[childMax] arr[cur]) break;--子树值大于根节点,需要调整,先交换根节点和子节点swap(arr, childMax, cur);cur = childMax; --根节点指针指向子节点,检查子节点是否满足大顶堆规则childMax = 2 * cur + 1; --子节点指针指向新的子节点步骤三:利用堆进行排序从后往前遍历大顶堆(数组),交换堆顶元素a[0]和当前元素a[i]的位置,将最大值依次放入数组末尾。
每交换一次,就要重新调整一下堆,从根节点开始,调整根节点~i-1个节点(数组长度为i),重新生成大顶堆-- 堆排序function heapSort(arr) {if (arr.length = 1) return arr;--构建大顶堆buildHeap(arr);--从后往前遍历,for (let i = arr.length - 1; i = 0; i--) {swap(arr, i, 0); --交换最后位置和第一个位置(堆顶最大值)的位置headAdjust(arr, 0, i); --调整根节点~i-1个节点,重新生成大顶堆return arr;完整代码:-- 交换数组元素function swap(a, i, j) {[a[i], a[j]] = [a[j], a[i]];--从输入节点处调整堆function headAdjust(arr, cur, len) {let intialCur = arr[cur]; --存放最初始的let childMax = 2 * cur + 1; --指向子树中较大的位置,初始值为左子树的索引--子树存在(索引没超过数组长度)而且子树值大于根时,此时不符合大顶堆结构,进入循环,调整堆的结构while (childMax len) {--判断左右子树大小,如果右子树更大,而且右子树存在,childMax指针指向右子树if (arr[childMax] arr[childMax + 1] childMax + 1 len) childMax++;--子树值小于根节点,不需要调整,退出循环if (arr[childMax] arr[cur]) break;--子树值大于根节点,需要调整,先交换根节点和子节点swap(arr, childMax, cur);cur = childMax; --根节点指针指向子节点,检查子节点是否满足大顶堆规则childMax = 2 * cur + 1; --子节点指针指向新的子节点-- 建立大顶堆function buildHeap(arr) {--从最后一个非叶子节点开始,向前遍历,for (let i = Math.floor(arr.length - 2 - 1); i = 0; i--) { headAdjust(arr, i, arr.length); --对每一个节点都调整堆,使其满足大顶堆规则-- 堆排序function heapSort(arr) {if (arr.length = 1) return arr;--构建大顶堆buildHeap(arr);--从后往前遍历,for (let i = arr.length - 1; i = 0; i--) {swap(arr, i, 0); --交换最后位置和第一个位置(堆顶最大值)的位置headAdjust(arr, 0, i); --调整根节点~i-1个节点,重新生成大顶堆return arr;public void testBubbleSort(){swap(L,j,j+1); --交换L-r[j]和L-r[j+1]的值record_point = malloc(length*sizeof(int));System.out.println("Please input integer["+(i+1)+"]");交换排序:两两比较待排序的关键字,并交换不满足次序要求的那对数,直到整个表都满足次序要求为止。