1. 冒泡排序
(1)如果在子循環中,不存在任何交換,說明數組已經排好序了;
(2)可以記錄子循環中交換的最大索引,次索引之後的元素都已經排好了。
// 冒泡排序
void bubbleSort(vector<int> &nums) {
int n = nums.size();
cout << n << endl;
int pos = 0;
for(int i = 0; i < n; i++) {
bool isSwap = false;
if(i < pos) {
i = pos;
}
for(int j = 0; j < n - i - 1; j++) {
if(nums[j] > nums[j+1]) {
swap(nums[j], nums[j+1]);
isSwap = true;
pos = n - j;
}
}
if(!isSwap) {
break;
}
}
}
2. 插入排序
(1)插入排序比一般O(n2)的排序算法快,因爲它會提前終止,這在實現時一定要加上;
(2)一種優化的方式:插入當前元素時,先找到位置,再交換,而不是一直交換,這樣效率高一些;
(3)對於基本有序的數組,插入排序特別高效,會進化成接近O(n)。
//插入排序
void insertionSort(vector<int> &nums) {
int n = nums.size();
for(int i = 0; i < n-1; i++) {
int pos = i+1;
int v = nums[pos];
for(int j = i + 1; j > 0; j--) {
if(v < nums[j-1]) {
//swap(nums[j], nums[j-1]);
nums[j] = nums[j-1];
pos--;
} else {
break;
}
}
nums[pos] = v;
}
}
3. 歸併排序
(1)優化1: 當左邊的最大元素小於右邊的最小元素時,無需排序;
(2)優化2:當待排序區間小於某個數時,使用插入排序完成(因爲數據越小,有序性越好,插入排序效果更好)。
//歸併排序
void mergeSort(vector<int> &nums) {
__mergeSort(nums, 0, nums.size()-1);
}
void __mergeSort(vector<int> &nums, int l, int r) {
if(l >= r) {
return;
}
int mid = (l + r) / 2;
__mergeSort(nums, l, mid);
__mergeSort(nums, mid+1, r);
if(nums[mid] > nums[mid+1])
merge(nums, l, mid, r);
}
void merge(vector<int> &nums, int l, int mid, int r) {
vector<int> tmp(r-l+1, 0);
int i = l, j = mid+1;
int k = 0;
while(i <= mid && j <= r) {
if(nums[i] <= nums[j]) {
tmp[k++] = nums[i++];
} else {
tmp[k++] = nums[j++];
}
}
while(i <= mid) {
tmp[k++] = nums[i++];
}
while(j <= r) {
tmp[k++] = nums[j++];
}
for(k = l; k <= r; k++) {
nums[k] = tmp[k-l];
}
return;
}
4. 快速排序
(1)快速排序的本質是每次排序找到key所在的位置,key位置左邊的元素小於它,右邊的元素大於它;
(2)快速排序的partition函數可以通過多種方式實現,又分爲普通partition,二路partition,三路partition;
(3)快速排序對於基本有序的數組排序效果很差,一種優化方法是對key進行隨機化(見代碼);
(4)當數組中存在大量重複元素時,普通快速排序效果很差,插入排序效果好。這時應該使用三路快速排序,效果比較好
(5)同樣地,一種優化方法是當排序區間小於某個數時,使用插入排序。
//快速排序(二路)
void quickSort(vector<int> &nums) {
srand(time(NULL));
__quickSort(nums, 0, nums.size() - 1);
}
void __quickSort(vector<int> &nums, int l, int r) {
if(l >= r) {
return;
}
int p = partition(nums, l, r);
__quickSort(nums, l, p - 1);
__quickSort(nums, p + 1, r);
}
int partition(vector<int> &nums, int l, int r) {
// 隨機在arr[l...r]的範圍中, 選擇一個數值作爲標定點pivot
swap(nums[l] , nums[rand()%(r-l+1)+l] );
int key = nums[l];
int i = l+1, j = r;
while(true) {
while(i <= r && nums[i] < key) {
i++;
}
while(j >= l+1 && nums[j] > key) {
j--;
}
if(i > j) {
break;
}
swap(nums[i], nums[j]);
i++;
j--;
}
swap(nums[l], nums[j]);
return j;
}