排序算法
下面主要实现了几个常见排序算法,只有代码没有分析,分析可参考如下:
十大经典排序:https://blog.csdn.net/weixin_41190227/article/details/86600821?spm=1001.2014.3001.5502
快速排序:https://blog.csdn.net/nrsc272420199/article/details/82587933
1.如何写算法程序
- 由简单到复杂
- 验证一步一步走
- 多打印中间结果
- 先局部后整体
- 没思路时先细分
- 先粗糙后精细
- 变量更名
- 语句合并
- 边界处理
验证算法 — 对数器
- 如何验证你的算法是否正确?
- 肉眼观察
- 产生足够多随机样本
- 用确定正确的算法计算样本结果
- 对比被验证算法的结果
排序算法复杂度及口诀
稳定性:任意两个相等的数据,排序前后的相对位置不发生改变
2. 时间复杂度下界
-
定理:任意N个不同元素组成的序列平均具有 N(N-1)/4个逆序对。
释:对于下标 i < j,如果A[i] > A[j],则称(i, j) 是一对逆序对。
-
定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为:Ω(N^2)。
Ω:下界;释:仅以交换相邻两元素来排序的算法最好最好最好时间复杂度为~N^2。
-
这意味着:要提高算法效率,我们必须
- 每次交换不止消去 1 个逆序对!
- 每次交换相隔较远的2个元素!
3. 排序算法实现
-
冒泡排序
冒泡排序每次按照一个方向扫描,并且交换相邻的两个元素(数组、链表均可),这是其他排序所不能比的。
冒泡排序的条件是 “>” 或 “<” ,因此是稳定的。
-
插入排序
T(N,T) = O(N + I) ——如果序列基本有序,则插入排序简单且高效。
-
希尔排序
插入排序的改进版—第一个突破O(n^2)的排序算法
具体操作
#include <iostream>
using namespace std;
#define MAXSIZE 100
typedef int ElemType;
struct SeqList {
ElemType data[MAXSIZE + 1];
int length;
};
void swap(SeqList* L, int i, int j)
{
int temp = L->data[i];
L->data[i] = L->data[j];
L->data[j] = temp;
}
void initList(SeqList* L)
{
L->length = 0;
}
void createList(SeqList* L)
{
int i = 1;
ElemType n;
while (cin >> n) {
L->data[i++] = n;
}
L->length = i - 1;
}
void show(SeqList L)
{
for (int i = 1; i <= L.length; ++i) {
cout << L.data[i] << " ";
}
cout << endl;
}
// !!!!data[0]是哨兵!!!!
// 冒泡排序
void bubbleSort(SeqList* L)
{
int i, j;
bool flag = true;
for (i = 1; i < L->length; ++i) {
flag = false;
for (j = L->length - 1; j >= i; --j) {
if (L->data[j] > L->data[j + 1]) {
swap(L, j, j + 1);
flag = true;
}
}
if (!flag) break;
}
}
// 插入排序
void insertionSort(SeqList* L)
{
int i, j;
for (i = 2; i <= L->length; ++i) {
if (L->data[i] < L->data[i - 1]) {
L->data[0] = L->data[i];
for (j = i - 1; L->data[j] > L->data[0]; --j) {
L->data[j + 1] = L->data[j];
}
L->data[j + 1] = L->data[0];
}
}
}
// 注意“D”,与上面插入对比
// 希尔排序---插入排序的改进版---第一个突破O(n^2)的排序算法
void shellSort(SeqList* L)
{
int j;
for (int D = L->length / 2; D > 0; D /= 2) {
for (int i = D; i < L->length; ++i) {
L->data[0] = L->data[i];
for (j = i; j >= D && L->data[j - D] > L->data[0]; j -= D) {
L->data[j] = L->data[j - D];
}
L->data[j] = L->data[0];
}
}
}
// 选择排序
void selectionSort(SeqList* L)
{
int i, j, min;
for (i = 1; i < L->length; ++i) {
min = i;
for (j = i + 1; j <= L->length; ++j) {
if (L->data[min] > L->data[j]) {
min = j;
}
}
if (i != min) {
swap(L, i, min);
}
}
}
// 堆排序---选择排序的改进
void heapAdjust(SeqList* L, int begin, int end)
{
ElemType temp = L->data[begin];
for (int j = 2 * begin; j <= end; j *= 2) {
if (j < end && L->data[j] < L->data[j + 1])
++j;
if (temp >= L->data[j])
break;
L->data[begin] = L->data[j];
begin = j;
}
L->data[begin] = temp;
}
void heapSort(SeqList* L)
{
int i;
for (i = L->length / 2; i > 0; --i)
heapAdjust(L, i, L->length);
for (i = L->length; i > 1; --i) {
swap(L, 1, i);
heapAdjust(L, 1, i - 1);
}
}
// 归并排序---- 2-路归并
void merge(SeqList* array, ElemType* tempArray, int start, int mid, int end)
{
int p1 = start, p2 = mid + 1, p = 0;
while (p1 <= mid && p2 <= end) {
if (array->data[p1] <= array->data[p2])
tempArray[p++] = array->data[p1++];
else
tempArray[p++] = array->data[p2++];
}
// 两个while只会执行一个
while (p1 <= mid)
tempArray[p++] = array->data[p1++];
while (p2 <= end)
tempArray[p++] = array->data[p2++];
for (int i = 0; i <= end - start; ++i)
array->data[i + start] = tempArray[i];
}
void MergeSort(SeqList* array, ElemType* tempArray, int start, int end)
{
if (start < end) {
int mid = start + (end - start) / 2;
MergeSort(array, tempArray, start, mid);
MergeSort(array, tempArray, mid + 1, end);
merge(array, tempArray, start, mid, end);
}
}
// 归并函数调用接口
void mergeSort(SeqList* array, int start, int end)
{
// 如果临时数组不放在这,到时候会爆栈!
ElemType* tempArray = new ElemType[end - start + 1];
if (tempArray) {
MergeSort(array, tempArray, start, end);
delete[] tempArray;
tempArray = nullptr;
}
else {
exit(-1);
}
}
// 快速排序
int partition(SeqList* L, int low, int high)
{
// 基准数据
ElemType key = L->data[low];
while (low < high) {
// 当队尾的元素大于等于基准时,向前移动high指针
while (low < high && L->data[high] >= key) {
high--;
}
// 退出循环时,队尾元素小于key了,需要赋值给low
L->data[low] = L->data[high];
//当队首元素小于等于key时,向后移动low指针
while (low < high && L->data[low] <= key) {
low++;
}
// 当队首元素大于等于key时,需要赋值给high
L->data[high] = L->data[low];
}
// 跳出循环时low和high相等,此时low / high就是key的正确索引位置
L->data[low] = key;
return low;
}
void quickSort(SeqList* L, int low, int high)
{
if (low >= high)
return;
int pivot = partition(L, low, high);
quickSort(L, low, pivot - 1);
quickSort(L, pivot + 1, high);
}