//
// 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
排序算法复习
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.