c++实现冒泡排序和快速排序
来源:互联网 发布:如何更改mysql的密码 编辑:程序博客网 时间:2024/06/07 14:57
上一篇博客中对插入排序进行了分析介绍,接下这里对冒泡排序和快速排序进行深入的分析介绍。冒泡排序和快速排序有个统称叫作“交换排序”,叫作交换排序的原因很容易理解,因为冒泡排序和快速排序都是通过多次交换两个数的位置从而达到排序的效果。接下来让我们好好理解下如何通过交换两个数的位置最终达到排序的效果。
注:介绍算法时仍然使用上一节用到的数据int a[10] = { 45, 12, 36, 76, 45, 9, 33, 19, 87, 23 };
交换排序算法的主要思想就是交换两个数据的位置。
1、冒泡排序
名如其意,冒泡排序的过程就像我们生活中看到的水中冒泡的现象一样,通过不断的交换将最大数据交换到顶端,然后再将次大的数据交换到倒数第二位,...,这样一个过程像是起泡一样。经过一轮冒泡排序将数组的最大的数据移到数组的最右端,然后再将次大数移到数组的倒数第二个位置....
从上述分析可知,给定n个数的数组,要经过 n-1 趟冒泡排序,其中每一趟排序都是从左到右进行将最大数据交换到右边去。
1.1 代码实现
#include<iostream>using namespace std;void BubbleSort(int *a, int n){for (int i = 0; i < n - 1; ++i){for (int j = 0; j < n - i - 1; ++j){if (a[j] > a[j + 1]){int temp = a[j];a[j] = a[j + 1];a[j + 1] = temp;}}}}int main(){int a[10] = { 45, 12, 36, 76, 45, 9, 33, 19, 87, 23 };cout << "排序前:";for (int i = 0; i < 10; ++i){cout << a[i] << " ";}cout << endl;BubbleSort(a, 10);cout << "排序后:";for (int i = 0; i < 10; ++i){cout << a[i] << " ";}cout << endl;return 0;}
1.2 排序结果
从上面的图可以看出,每一趟排序将一个大的数据从左到右交换到右边。并且算法是稳定的。
1.3 性能分析
因为冒泡排序需要经过 n-1 趟排序,每一趟排序都要从左端开始往右将每两个相邻元素进行比较,总的时间复杂度为O(n^2)。
1.4 冒泡排序的改进
从上面例子可以看出当进行完第6趟排序后已经达到最终的排序效果,后面的第7,8,9趟排序没有交换元素。因此针对这一点我们可以对冒泡排序进行改进,从一定程度上能够起到加速的效果,改进思想如下:
如果在某一趟排序中没有交换数据的操作,数据已经有序,我们可以提前终止。
在代码的实现上很简单,在每一趟排序开始的时候只用加一个bool变量用以标价该趟排序过程中是否有元素的交换即可。这样可以达到提前终止的效果,从而减少后面不必要的比较。
改进后的代码
#include<iostream>using namespace std;void BubbleSort(int *a, int n){for (int i = 0; i < n - 1; ++i){bool f = false;for (int j = 0; j < n - i - 1; ++j){if (a[j] > a[j + 1]){f = true;int temp = a[j];a[j] = a[j + 1];a[j + 1] = temp;}}if (!f) break;}}int main(){int a[10] = { 45, 12, 36, 76, 45, 9, 33, 19, 87, 23 };cout << "排序前:";for (int i = 0; i < 10; ++i){cout << a[i] << " ";}cout << endl;BubbleSort(a, 10);cout << "排序后:";for (int i = 0; i < 10; ++i){cout << a[i] << " ";}cout << endl;return 0;}改进后的效果
改进后我们可以提前终止,只进行了7趟排序,就往成了任务。
2、快速排序
个人感觉快速排序就是一个“挖坑填数”的思想。何谓挖坑填数呢,就是在数组中挖掉一个数,然后将另一个满足条件的数据填到这个坑里。下面我们通过例子说明这样一个过程。
2.1 基本步骤
快速排序可以分为三个步骤:
(1)选择基准元素;
(2)以基准元素为准将数据分割为左右两部分,基准元素左边的数据要比基准元素小,基准元素右边的数据比基准元素大;
(3)然后对基准元素左边、右边分别使用快速排序。(递归的一个过程)
下面我们分别针对这三个步骤分别做详细地说明:
对于步骤(1),通常情况下我们会以数组最左端的数据作为基准元素。后面我们分析快速排序算法的性能时,再对基准元素的选择做详细分析。
对于步骤(2),我们需要设两个指针分别指向数组的两端,使用一个临时变量存放基准元素(相当于挖了一个坑)。然后右端指针开始向左移动,找到第一个比基准元素小的数据并将该数据填到坑中(相当于填了一坑又挖了一个坑),这是右端指针所指的地方出现了一个坑。然后向右动左侧指针,找到第一个比基准元素大的数据,并将其填到坑中(填了一个坑又又挖了一个坑)。然后向左移动右侧指针....,这样当左边指针和右边指针指向同一位置时将临时保存的数据填到这个位置上就完成了第一趟快速排序,此时基准元素左边的小于基准元素,右边的大于基准元素。
对于步骤(3),是一个递归的过程,分别对左边右边使用快速排序。
2.2 实现代码
#include<iostream>using namespace std;//选择一个基准元素,进行一次划分int partition(int start, int end, int *a){int temp = a[start];while (start < end){while (start < end && a[end] >= temp){--end;}a[start] = a[end];while (start < end && a[start] <= temp){++start;}a[end] = a[start];}a[start] = temp;return start;}void QuickSort(int start, int end, int *a){if (start < end){int middle = partition(start, end, a);QuickSort(start, middle - 1, a);//对左侧递归调用QuickSort(middle + 1, end, a);//对右侧递归调用}}void print(int *a, int n){for (int i = 0; i < n; ++i){cout << a[i] << " ";}cout << endl;}int main(){int a[10] = { 45, 12, 36, 76, 45, 9, 33, 19, 87, 23 };print(a, 10);QuickSort(0, 9, a);print(a, 10);return 0;}
2.3 排序结果
具体的排序过程如下:
第一趟快速排序:
第二趟快速排序:
第三趟快速排序:
第四趟快速排序:
第五趟快速排序:
经过5趟快速排序完成数据排序。通过例子可以观察到第3趟排序后,数据已经达到最后的排序效果,因此我们可以采取某些策略使得快速排序提前停止,进而调高性能。
2.4 性能分析
快速排序的平均时间复杂度为O(n*logn)。但是当待排序数据已经基本有序时,快速排序退化成冒泡排序,此时时间复杂度为O(n^2)。
2.5 快速排序改进
快速排序可以改进的地方:
(1)基准元素的选取;
选择基准元素时,通常使用“三者取其中”的方法。也就是说根据给定的start和end,我们通常使用中间位置的数据最为基准元素。
(2)在一次划分过程中,可以提前结束
在指针start加1和end减1的过程中都进行“起泡操作”,即每移动一次指针我们就比较两个相邻数据是否“逆序”,如果逆序就交换他们的位置。另外设一个bool变量用于标记是否发生了“起泡”的交换操作,如果没有发生说明不许要对这一端再进行排序,从而达到提前结束的效果。
- 冒泡排序和快速排序(Object-C)
- 冒泡排序和快速排序java实现
- PHP实现冒泡排序和快速排序
- c++实现冒泡排序和快速排序
- js实现冒泡排序和快速排序
- C++实现快速排序和冒泡排序
- java实现冒泡排序和快速排序
- java实现冒泡排序和快速排序
- C语言分别实现冒泡排序、快速排序、选择排序
- Scala实现冒泡排序、归并排序和快速排序
- Scala实现冒泡排序、归并排序和快速排序
- 冒泡排序,shell排序和快速排序算法实现
- Java实现交换排序 之 冒泡排序和快速排序
- 快速排序和冒泡排序
- 冒泡排序和快速排序
- 冒泡排序和快速排序
- 冒泡排序和快速排序
- 冒泡排序和快速排序
- opendir打开后显示的不全
- ES性能调优
- JDBC连接MySql
- 逆向工程核心原理学习笔记(二十二):栈帧9:调用printf()函数
- Coprime Sequence
- c++实现冒泡排序和快速排序
- MEASURING COMPUTER PERFORMANCE
- 领域模型(概念模型) 、逻辑模型、物理模型、贫血模型、充血模型概念总结【待读与标记】
- linux shell 字符串操作(长度,查找,替换)详解
- 百度实习生面试题-按行读取文件
- 记一次 php nginx 502 504 大坑
- 位图
- 【读书笔记】机器学习实战 5.2节 logistics回归
- 设计模式之责任链模式