#include<iostream>
#include<vector>
using namespace std;
//冒泡排序的特點:每一輪冒泡過後,在過去一輪遍歷中訪問過的元素中的最大元素
//一定會到達它最終應當處在的位置。
//基礎版本的冒泡排序:雙循環。外層循環控制冒泡次數,內層循環實現每一輪的
//冒泡處理:先進行元素比較,再進行元素交換。
void bubbleSort_1(vector<int> &nums){
int length=nums.size();
for(int i=0;i<length-1;i++){
for(int j=0;j<length-1-i;j++){
if(nums[j]>nums[j+1]){
int temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
return;
}
//第一種版本的冒泡排序的問題是:序列可能會提前達到有序,所以該版本會出現不必要的時間開銷,
//所以第二種版本的優化思路是:記錄每輪冒泡過程中是否出現元素交換,若無,說明序列已有序,結束排序。
void bubbleSort_2(vector<int> &nums){
int length=nums.size();
for(int i=0;i<length-1;i++){
//有序標記,每一輪的初始值都是true
bool isSorted=true;
for(int j=0;j<length-1-i;j++){
if(nums[j]>nums[j+1]){
int temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
//因爲有元素交換,所以不是有序的,標記變爲false
isSorted=false;
}
}
//若isSorted=true,說明已有序,故跳出循環,排序結束
if(isSorted){
break;
}
}
}
//按照前兩種方法的邏輯,每輪冒泡結束後,序列最右側會形成一個有序區,且有序區的長度等於冒泡截止到當前所進行的輪數
//但是實際上右側的有序區的長度可能會大於輪數,因此會有不必要的比較發生,造成時間上的浪費。所以,針對此問題提出的優化方案是:
//維護一個變量,記錄下無序數列的邊界,邊界往後就是有序區
void bubbleSort_3(vector<int> &nums){
int length=nums.size();
//記錄最後一次交換的位置
int lastExchangeIndex=0;
//無序區的邊界,每次只需比較到這裏爲止
int sortBorder=length-1;
for(int i=0;i<length-1;i++){
//有序標記:每一輪的初始值都是true
bool isSorted=true;
for(int j=0;j<sortBorder;j++){
if(nums[j]>nums[j+1]){
int temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
//因爲有元素的交換。所以不是有序的,標記變爲false
isSorted=false;
//更新最後一次交換元素的位置
lastExchangeIndex=j;
}
}
//更新無序區的邊界
sortBorder=lastExchangeIndex;
if(isSorted){
break;
}
}
}
void printArray(vector<int> nums){
for(int i=0;i<nums.size();i++){
cout<<nums[i]<<" ";
}
cout<<endl;
}
int main()
{
vector<int> nums_1,nums_2,nums_3;
//生成三個降序序列以備測試,設置成降序是爲了賦值方便,因爲本代碼旨在介紹冒泡排序這種算法
//而不是用實例測試排序算法優化後的性能,所以採取這種簡便但是可能不夠合理的賦值方法
for(int i=0;i<5;i++){
nums_1.push_back(5-i);
nums_2.push_back(6-i);
nums_3.push_back(7-i);
}
bubbleSort_1(nums_1);
//打印排序後的nums_1
printArray(nums_1);
bubbleSort_2(nums_2);
//打印排序後的nums_2
printArray(nums_2);
bubbleSort_3(nums_3);
//打印排序後的nums_3
printArray(nums_3);
return 0;
}