//
// Created by NickWang on 2019/8/24.
//
/*
直接插入排序-----O(n^2)
折半插入排序-----O(n^2)
冒泡排序--------O(n^2)
快速排序--------O(nlogn)
選擇排序--------O(n^2)
堆排序----------O(nlogn)
歸併排序--------O(nlogn)
*/
#ifndef C_SORT_H
#define C_SORT_H
#include <iostream>
#include <vector>
using namespace std;
class Sort {
public:
/*
* 直接插入排序 O(n^2)
* 算法思想:將記錄集合分爲有序和無序兩個序列。
* 從無序序列中任取一個記錄,根據大小插入到有序序列的合適位置,使得該序列插入後仍然有序。
* 每插入一個記錄稱爲一趟插入排序,無序記錄全部插入有序序列後,排序完成
*/
void DirectInsert(int data[], int n){
for (int i = 1; i < n; ++i) { // 一共執行n-1趟
int currentNum = data[i]; // 保存當前處理的值
int index = i - 1; // 記錄上一個值得索引號
// 從上一個開始往前找,只要比當前處理的數大,就將數值後移
while (index >= 0 && currentNum < data[index])
{
data[index + 1] = data[index];
index--;
}
data[index + 1] = currentNum;
}
}
/*
* 折半插入排序 O(n^2)
* 算法思想:在直接插入排序的基礎上,由於有序序列可以折半查找,找到合適位置後進行移位。
*/
void BinaryInsert(int data[], int n){
int low, high, mid, currentNum;
for (int i = 1; i < n; ++i) { // 一共執行n-1趟
low = 0;
high = i - 1;
currentNum = data[i];
while (low <= high){
mid = (low + high) / 2;
if (currentNum < data[mid]){
// 在前半段
high = mid - 1;
} else {
low = mid + 1;
}
}
// 插入位置爲high + 1
for (int j = i - 1; j >= high + 1; --j) {
data[j + 1] = data[j];
}
data[high + 1] = currentNum;
}
}
/*
* 冒泡排序 O(n^2)
* 算法思想:兩兩比較待排記錄大小,發現逆序,交換兩個記錄,直到表中沒有逆序記錄存在
*/
void BubbleSort(int data[], int n){
int swap = 0;
for (int i = 0; i < n - 1; ++i) { // 一共執行n-1趟
for (int j = 1; j < n - 1 - i; ++j) {
if (data[j - 1] > data[j]){
int temp = data[j - 1];
data[j - 1] = data[j];
data[j] = temp;
swap = 1;
}
}
// 沒有進行交換,說明已經排好序
if (swap == 0){
break;
}
}
}
/*
* 快速排序 O(nlogn)
* 算法思想:在待排序列中任取一個記錄,以該記錄爲基準,經過一趟交換後,
* 所有比記錄小的都在左邊,比記錄大的都在右邊。
* 然後在對左右兩部分重複上述步驟。
*/
int Partition(int data[], int i, int j){
// 保存基準數據
int baseNum = data[i];
while (i < j){
// 從j開始從右往左找第一個比基準小的數據
while (i < j && data[j] > baseNum)
j--;
if (i < j){
// 找到第一個比baseNum小的數字,將小數放到左邊界,左邊界右移,i++
data[i] = data[j];
i++;
}
// 從左邊界開始往右找第一個比基準大的數據
while (i < j && data[i] < baseNum)
i++;
if (i < j){
// 找到第一個比baseNum大的數字,將大數放到右邊界,右邊界左移,--j
data[j] = data[i];
--j;
}
}
// i 的位置就是基準數據該在的位置
data[i] = baseNum;
return i;
}
void QuickSort(int data[], int low, int high){
if (low < high){
int location = Partition(data, low, high);
QuickSort(data, low, location - 1);
QuickSort(data, location + 1, high);
}
}
/*
* 選擇排序 O(n^2)
* 算法思想:每一趟選擇待排記錄中最小的記錄,並放入已排序序列的末尾,
* 直至全部記錄完成。
*/
void SelectSort(int data[], int n){
for (int i = 0; i < n - 1; ++i) {
int min = i;
for (int j = i + 1; j < n; ++j) {
if (data[j] < data[min])
min = j;
}
if (min != i){
int temp = data[min];
data[min] = data[i];
data[i] = temp;
}
}
}
/*
* 堆排序 O(nlogn)
* 算法思想:(小頂堆爲例)由堆頂可以得到最小值,然後將其移除,
* 對剩餘n-1個節點進行調整,重新成爲一個堆,再從堆頂獲取最小值。
* 當堆只剩下一個數據的時候,將其移除後就排成有序序列。
*
* 數組存儲二叉樹說明:
* 父節點序號爲i,2i爲其左孩子,2i+1爲其右孩子 (從1開始存)
* 共n個節點,則大於n/2的節點開始爲葉子節點
*
* 建立初始堆:
* 大於n/2的節點爲葉子節點,本事滿足堆的定義。
* 於是從n/2節點開始,將其調整爲堆。然後對n/2-1調整爲堆。
* 對節點i調整過程中,調整時可能使本來滿足堆定義的子樹不再滿足,
* 於是需要逐層向下進行調整。
*
* 堆頂去除後,剩餘n-1節點調整成新堆:
* 將序號爲n的節點與堆頂交換,這時只需要使1~n-1滿足堆的定義,
* 即可將剩餘n-1節點構成堆。這時對堆頂元素進行自上而下的調整。
* 調整方法:將根節點與左右孩子中較小的交換,然後繼續對交換後的子樹進行交換,
* 直到交換到葉子節點。
*/
void HeapAdjust(int data[], int begin, int end){
data[0] = data[begin]; // 保存堆頂元素
int currentIndex = begin; // 保存正在操作的節點序號
// 堆頂元素從較小的孩子開始向下調整
for (int i = 2 * begin; i <= end; i = i * 2) {
if (i < end && data[i] > data[i + 1]){
// 左孩子比右孩子大
i = i + 1; // 選擇較小的
}
if (data[0] < data[i]){
// 此時堆頂的最小,則無需向下調整
break;
}
data[currentIndex] = data[i];
currentIndex = i;
}
data[currentIndex] = data[0]; // 將堆頂放到合適位置
}
void HeapSort(int data[], int n){
for (int i = n / 2; i > 0; --i) {
HeapAdjust(data, i, n);
}
// 每一趟堆頂和最後一個換
for (int i = n; i > 1; --i) {
// data[1]和當前最後一個data[i]進行交換
data[0] = data[1];
data[1] = data[i];
data[i] = data[0];
HeapAdjust(data, 1, i - 1);
}
}
/*
* 歸併排序 O(nlogn)
* 算法思想:只有一個記錄的表是有序的,開始將n個記錄看成n個表,每個表有序。
* 第一趟二路歸併將表1和表2,表3和表4,...,表n-1和表n進行歸併,得到長度爲2的表。
* 繼續重複得到長度爲4的表,...,直到最後將整個表歸併。
*/
void merge(int data[], int retData[], int begin, int mid, int end){
// 將有序表data[begin:mid]與data[mid:end]合併成一個有序表retData[begin:end]
int i = begin;
int j = mid + 1;
int k = begin;
while (i <= mid && j <= end){
if (data[i] < data[j])
retData[k++] = data[i++];
else
retData[k++] = data[j++];
}
// data[begin:mid]還沒有完
while (i <= mid){
retData[k++] = data[i++];
}
// data[mid:end]還沒有完
while (j <= end){
retData[k++] = data[j++];
}
}
void MergeSort(int data[], int retData[], int begin, int end){
// 將無序表data[begin:end]合併成有序表retData[begin:end]
int tempData[255];
if (begin == end){
retData[begin] = data[begin];
} else {
int mid = (begin + end) / 2;
MergeSort(data, tempData, begin, mid);
MergeSort(data, tempData, mid + 1, end);
merge(tempData, retData, begin, mid, end);
}
}
};
#endif //C_SORT_H
排序算法複習
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.