冒泡排序
冒泡排序是一种极其简单的排序算法,也是必须学的第一个排序算法。它重复地走访过要排序的元素,依次比较相邻两个元素,如果他们的顺序错误就把他们调换过来,直到没有元素再需要交换,排序完成。这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序算法的运作如下:
- 比较相邻的元素,如果前一个比后一个大,就把它们两个调换位置。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
由于它思想的简洁,冒泡排序通常被用来对于程序设计入门的学生介绍算法的概念。冒泡排序的代码如下:
vector<int> bubble_sort(const vector<int>& arr){
vector<int> arr_temp = arr;
int n_compare=0 , n_swap = 0;
for (int i = 0; i < arr_temp.size() - 1; i++){
for (int j = 0; j < arr_temp.size() - i-1; j++){
n_compare++;
if (arr_temp[j] > arr_temp[j + 1]){
n_swap++;
int temp = arr_temp[j];
arr_temp[j] = arr_temp[j + 1];
arr_temp[j + 1] = temp;
}
}
}
cout << "method:bubble_sort n_compare:"<< n_compare << " n_swap:"<< n_swap << endl;
return arr_temp;
}
根据冒泡法的思想,相继提出了两种改进的冒泡算法。
冒泡改进:鸡尾酒排序算法
鸡尾酒排序,也叫定向冒泡排序,是冒泡排序的一种改进。此算法与冒泡排序的不同处在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能。
鸡尾酒排序的代码如下:
vector<int> bubble_sortImprove2(const vector<int>& arr){
vector<int> arr_temp = arr;
int n_compare = 0, n_swap = 0;
int begin = 0, end = arr_temp.size();
while (begin < end){
for (int i = begin; i < end-1; i++){
n_compare++;
if (arr_temp[i] > arr_temp[i + 1]){
n_swap++;
int temp = arr_temp[i];
arr_temp[i] = arr_temp[i + 1];
arr_temp[i + 1] = temp;
}
}
end--;
for (int j = end-1; j > begin; j--){
n_compare++;
if (arr_temp[j] < arr_temp[j - 1]){
n_swap++;
int temp = arr_temp[j];
arr_temp[j] = arr_temp[j - 1];
arr_temp[j - 1] = temp;
}
}
begin++;
}
cout << "method:bubble_sortImprove2 n_compare:" << n_compare << " n_swap:" << n_swap << endl;
return arr_temp;
}
冒泡改进:优良改进
根据冒泡算法的交换特性,假如最后一部分是有序,则不会产生交换,所以我们可以根据上一次的比较交换位置来判断下一次需要比较与否。你会发现假如是一个本身有序(你想要的那个升/降序列)的序列,则该改进只需要比较n次就行了。
代码如下:
vector<int> bubble_sortImprove1(const vector<int>& arr){
vector<int> arr_temp = arr;
int n_compare = 0, n_swap = 0;
int current;
int last = arr_temp.size()-1;
while (0 < last){
for (int i = current = 0; i < last; i++){
n_compare++;
if (arr_temp[i] > arr_temp[i + 1]){
n_swap++;
int temp = arr_temp[i];
arr_temp[i] = arr_temp[i + 1];
arr_temp[i + 1] = temp;
current = i;
}
}
last = current;
}
cout << "method:bubble_sortImprove1 n_compare:" << n_compare << " n_swap:" << n_swap << endl;
return arr_temp;
}
彼此比较
再来看看比较的整体代码:
#include<stdlib.h>
#include<iostream>
#include<random>
#include<algorithm>
#include<vector>
#include<numeric>
#include<time.h>
#include<Windows.h>
using namespace std;
void arr_get(vector<int>& up_temp, vector<int>& down_temp){
sort(up_temp.begin(), up_temp.end());
sort(down_temp.rbegin(), down_temp.rend());
}
void print_vector(vector<int>& ve){
for (int i = 0; i < ve.size(); i++){
cout << ve[i] << " ";
}
cout <<"\n"<< endl;
}
vector<int> bubble_sort(const vector<int>& arr){
vector<int> arr_temp = arr;
int n_compare=0 , n_swap = 0;
for (int i = 0; i < arr_temp.size() - 1; i++){
for (int j = 0; j < arr_temp.size() - i-1; j++){
n_compare++;
if (arr_temp[j] > arr_temp[j + 1]){
n_swap++;
int temp = arr_temp[j];
arr_temp[j] = arr_temp[j + 1];
arr_temp[j + 1] = temp;
}
}
}
cout << "method:bubble_sort n_compare:"<< n_compare << " n_swap:"<< n_swap << endl;
return arr_temp;
}
vector<int> bubble_sortImprove1(const vector<int>& arr){
vector<int> arr_temp = arr;
int n_compare = 0, n_swap = 0;
int current;
int last = arr_temp.size()-1;
while (0 < last){
for (int i = current = 0; i < last; i++){
n_compare++;
if (arr_temp[i] > arr_temp[i + 1]){
n_swap++;
int temp = arr_temp[i];
arr_temp[i] = arr_temp[i + 1];
arr_temp[i + 1] = temp;
current = i;
}
}
last = current;
}
cout << "method:bubble_sortImprove1 n_compare:" << n_compare << " n_swap:" << n_swap << endl;
return arr_temp;
}
vector<int> bubble_sortImprove2(const vector<int>& arr){
vector<int> arr_temp = arr;
int n_compare = 0, n_swap = 0;
int begin = 0, end = arr_temp.size();
while (begin < end){
for (int i = begin; i < end-1; i++){
n_compare++;
if (arr_temp[i] > arr_temp[i + 1]){
n_swap++;
int temp = arr_temp[i];
arr_temp[i] = arr_temp[i + 1];
arr_temp[i + 1] = temp;
}
}
end--;
for (int j = end-1; j > begin; j--){
n_compare++;
if (arr_temp[j] < arr_temp[j - 1]){
n_swap++;
int temp = arr_temp[j];
arr_temp[j] = arr_temp[j - 1];
arr_temp[j - 1] = temp;
}
}
begin++;
}
cout << "method:bubble_sortImprove2 n_compare:" << n_compare << " n_swap:" << n_swap << endl;
return arr_temp;
}
void main(){
vector<double> time_count;
for (int j = 0; j < 10; j++){
vector<int> a = {};
static uniform_int_distribution<unsigned> u(0, 10000);
static default_random_engine e;
for (int i = 0; i < 10000; i++){
a.push_back(u(e));
}
vector<int> up(a);
vector<int> down(a);
arr_get(up, down);// 预留测试最好最坏情况
time_t time_start = time(NULL);
vector<int> a_sort = bubble_sort(a);
time_t time_end = time(NULL);
time_count.push_back((double)difftime(time_end, time_start));
time_start = time(NULL);
vector<int> a1_sort = bubble_sortImprove1(a);
time_end = time(NULL);
time_count.push_back((double)difftime(time_end, time_start));
time_start = time(NULL);
vector<int> a2_sort = bubble_sortImprove2(a);
time_end = time(NULL);
time_count.push_back((double)difftime(time_end, time_start));
//print_vector(c_sort);
}
int sum_time1 = 0, sum_time2 = 0,sum_time3 = 0;
for (int i = 0; i < time_count.size(); i+=3){
sum_time1 += time_count[i];
sum_time2 += time_count[i+1];
sum_time3 += time_count[i+2];
cout << time_count[i] << " " << time_count[i + 1] << " " << time_count[i + 2] << "\n";
}
cout << "method:bubble_sort time(s):" << sum_time1 / ((double)time_count.size() / 3.0)
<< " " << "method:bubble_sortImprove1 time(s):" << sum_time2 / ((double)time_count.size() / 3.0)
<< " " << "method:bubble_sortImprove2 time(s):" << sum_time3 / ((double)time_count.size() / 3.0) << endl;
system("pause");
}
结果:
我们可以看到其实鸡尾酒排序没有改变比较和交换的次数,但是时间上来说还是比原来的要快,真正原因难说。
而我们的优良改进是从原理上改进,无论是比较次数还是时间都是优秀的。