# 排序演算法
## Bubble sort(泡沫排序法)
泡沫排序法是一個很直觀且簡易的一種排序算法,以升冪從未排序的第一筆開始,第一筆資料和第二筆做交換,如果第二筆大於第三筆,就將第二筆和第三筆交換,以此類推。
Time complexity :O(n^2)
```cpp=
#include <iostream>
#include <vector>
using namespace std;
int main(){
int counts;
while(cin >> counts){
vector<int> vec;
int temp;
for(int i = 0;i < counts;i++){
cin >> temp;
vec.push_back(temp);
}
for(int i = 0;i < counts;i++){
for(int k = 0;k < counts-1;k++){
if(vec[k] > vec[k+1])
swap(vec[k],vec[k+1]);
}
}
for(int i = 0 ;i < counts;i++){
cout << vec[i] << " ";
}
cout << endl;
}
return 0;
}
```
## Merge sort(合併排序法)
merge sort 是一個運用divide and conquer 演算法的演算法,先將問題分為數個子問題,最後再結合起來就會是問題的答案了。
<span style = "color:red">time complexity : O(nlogn)</span>
```cpp=
#include <iostream>
#include <vector>
using namespace std;
long long int infinity = 999999999;
void merge(vector<int> &vec,int first,int mid,int last){
vector<int> left_area(vec.begin()+first,vec.begin()+mid+1);
vector<int> right_area(vec.begin()+mid+1,vec.begin()+last+1);
left_area.emplace(left_area.end(),infinity);
right_area.emplace(right_area.end(),infinity);
int left_idx = 0,right_idx = 0;
for(int i = first;i <= last;i++){
if(left_area[left_idx] <= right_area[right_idx]){
vec[i] = left_area[left_idx];
left_idx++;
}
else{
vec[i] = right_area[right_idx];
right_idx++;
}
}
}
void merge_sort(vector<int> &vec,int first,int last){
if(first < last){
int mid = (first+last)/2;
merge_sort(vec,first,mid);
merge_sort(vec,mid+1,last);
merge(vec,first,mid,last);
}
}
int main(){
vector<int> vec{48,23,19,34,65,20,3};
cout << "original : ";
for(int i = 0;i < vec.size();i++)
cout << vec[i] << " ";
cout << endl;
cout << "After merge sort : ";
merge_sort(vec,0,7);
for(int i = 0;i < vec.size();i++)
cout << vec[i] << " ";
return 0;
}
```
首先使用vector來儲存資料,接著把vector加入merge_sort()函式,merge_sort主要運行遞迴,前面有說merge_sort是將大問題分為數個子問題,而此遞迴就是為了實現此方式,首先將矩陣分為兩個,各自再分為兩個,一直分到不能分為止,此時停止遞迴,接著合併各個矩陣,在第6行和第7行是vector的constructor,將兩個矩陣分別放入left_area和right_area,然後用emplace把一個極大的數字插在他們的最後的地方,然後開始比較,兩個不同的vector用兩個不同的指標,把小的依序擺下來,擺好後在和下一個比,直到完成排序,這樣就完成merge_sort了。
## Quick sort(快速排序法)
quick sort是一個運用divide and conquer 演算法的演算法,而隸屬於algorithm這個函式庫中有一個函式sort()就是利用quick sort,這是別人寫好的,可以接利用,首先先介紹這個函式,這個函式可加入三個參數,第一個參數是陣列或向量的第一個值,而第二個值是陣列或向量的最後一個值,第三個參數可有可無,是放入自訂函式,決定升冪或降冪,或當陣列或向量並不純,而是有和結構做連接,所以此時適合加入第三個參數,幫助解決。
<span style = "color:red">time complexity : O(nlogn)
但是worst case的時候是O(n^2)</span>
```cpp=
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
struct data{
int a;
int b;
};
bool cmp(data x,data y){
if(x.a == y.a) return x.b < y.b;
else return -1;
}
int main(){
data foo[10];
srand(time(NULL));
for(int j = 0;j < 10;j++)
foo[j].a = 0;
for(int i = 0;i < 10;i++){
foo[i].b = rand()%1000;
}
sort(foo,foo+10,cmp);//此處加入第三個參數
for(int i = 0;i < 10;i++)
cout << foo[i].b << " ";
return 0;
}
```
但是不能只會用別人的東西,自己也要會寫,所以接下來要介紹quick sort是如何運行的。
```cpp=
#include <bits/stdc++.h>
using namespace std;
void quick_sort(int *arr,int front_,int end_);
void swap_(int *a,int *b);
int partition_(int *arr,int front_,int end_);
int main(){
int arr[10] = {3,5,7,2,13,21,6,1};
for(int i = 0;i < 8;i++)
cout << arr[i] << " ";
cout << endl;
quick_sort(arr,0,7);
for(int i = 0;i < 8;i++)
cout << arr[i] << " ";
return 0;
}
void swap_(int *a,int *b){
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void quick_sort(int *arr,int front_,int end_){
if(front_ < end_){
int pivot = partition_(arr,front_,end_);
quick_sort(arr,pivot+1,end_);
quick_sort(arr,front_,pivot-1);
}
}
int partition_(int *arr,int front_,int end_){
int pivot = arr[end_];
int i = front_-1;
for(int j = front_;j < end_;j++){
if(arr[j] < pivot){//to control ascending power and Descending powers
i++;
swap_(&arr[i],&arr[j]);
}
}
i++;
swap_(&arr[i],&arr[end_]);
return i;
}
```
quick sort有一個很重要的東西,就是pivot,他就像一個標準,每個值要和他比較,在他左邊的值是比他小的,在他右邊是比他大的,保持這個特性一直做下去,而我們的pivot會採用陣列裡最後一個值,沒有強制規定要找哪一個,而在partition_裡的迴圈作用是一個一個做比較,最後再將pivot插入中間,以得到在他左邊的值是比他小的,在他右邊是比他大的。而quick_sort函式裡是一個遞迴,一直重複直到無法再分到更小的,這邊和merge sort有幾分相似。
## 總結
我覺得排序演算法是一堂很重要的課,也是進入演算法世界的第一把鑰匙,表面上在排序,但實際上有許多的觀念在背後,其實排序演算法有很多,但我這邊就舉三個例子即可,學玩排序後就來學搜尋吧!