对现有工作并不是很满意,所以决定找下一个坑。由工作中遇到排序场景并不多,大都是用冒泡排序,太low,面试又经常问到一些排序算法方面的东西。刚好让小学妹邮的数据结构也到了。就把各种排序算法重新总结一下,以作留存。
排序分为内部排序和外部排序,内部排序是在内存中排序。外部排序是由于排序记录量太大,内存一次放不下全部记录,排序过程中需要对外部存储访问的排序过程。外部排序用到的场景比较少,所以本次总结的都是内部排序。
排序安全:相同的元素相对位置不变,是排序安全,反之是不安全。
一,直接插入排序
基本思路:把一个元素插入到已排好的有序表中。(初始时认为是只有一个有序元素为有序表和其他无序元素)
应用场景:基本有序时复杂度为n。
是否排序安全:安全。
复杂度:O(n2).
代码:
//直接插入排序
void CSort::InsertSort(int *a, int len)
{
for (int i = 1; i < len; i++)
{
int key = a[i];
int j = i - 1;
//当前元素做为key
while (j>=0 && a[j] > key)
{
//不是元素应当插入时的位置,全部后移
a[j + 1] = a[j];
j--;
}
//插入元素到正确位置
a[j+1] = key;
}
}
二,希尔排序
希尔排序是直接插入排序的改进。
基本思路:先将整个待排序记录按照增量分割成若干子序分别进行插入排序,基本有序时在进行一次直接插入排序。
实现:先使增量为长度的一半,在让增量变为增量的一半,使序列逐渐有序,增量为1时,等于对基本有序数列进行一次直接插入排序。
应用场景:基本有序时复杂度为n。
是否排序安全:不安全。
复杂度:O(n2).
代码:
//希尔插入,当增量为1时就是直接插入排序
void CSort::ShellInsert(int *a, int len, int dk)
{
for (int i = dk + 1; i < len; i++)
{
int key = a[i];
int j = i - dk;
while (j >= 0 && a[j] > key)
{
a[j +dk] = a[j];
j -= dk;
}
a[j + dk] = key;
}
}
//希尔排序
void CSort::ShellSort(int *a, int len)
{
int k = len / 2;
while (k >= 1)
{
ShellInsert(a, len, k);
k = k / 2;
}
}
三,冒泡排序
基本思路:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
是否排序安全:安全
代码:
void CSort::BubbleSort(int *a, int len)四,快速排序。(冒泡排序的优化)
基本思路:选取一个元素, 把表里的元素依次对比选取的元素,分割成2个表(此时元素以在最终的位置)。在依次对这两个表进行重复操作。次元素所在的位置就是最终其应该在的位置。当表里的元素数量为1时结束。
适用场景:快速排序是平均复杂度最低的排序。
是否排序安全:不安全
代码:
//快速排序
int CSort::Partition(int *a, int low, int high)
{
int key = a[low];
while (low < high)
{
while (low < high&&a[high] >= key) high--;
swap(&a[low],&a[high]);
while (low < high&&a[low] <= key) low++;
swap(&a[low],&a[high]);
}
return low;
}
void CSort::QuickSort(int *a, int low, int high)
{
if (low
int index = Partition(a, low, high);
QuickSort(a, low, index - 1);
QuickSort(a, index + 1, high);
}
}
五,选择排序(简单选择排序)。
基本思路:每一趟循环都选择最小(大)的元素作为有序数列的第i个元素。
适用场景:
是否排序安全:不安全
代码:
void CSort::SelectSort(int *a, int len)六,归并排序。
基本思路:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并排序示例:
复杂度:O(n)
使用场景:适用于很多元素而且无序的排序。
代码:
void CSort::Merge(int *r, int *rf, int i, int m, int n)
{
int j, k;
for (j = m + 1, k = i; i <= m && j <= n; ++k){
if (r[j] < r[i]) rf[k] = r[j++];
else rf[k] = r[i++];
}
while (i <= m) rf[k++] = r[i++];
while (j <= n) rf[k++] = r[j++];
}
void CSort::MergeSort(int *r, int *rf, int lenght)
{
int len = 1;
int *q = r;
int *tmp;
while (len < lenght) {
int s = len;
len = 2 * s;
int i = 0;
while (i + len < lenght){
Merge(q, rf, i, i + s - 1, i + len - 1); //对等长的两个子表合并
i = i + len;
}
if (i + s < lenght){
Merge(q, rf, i, i + s - 1, lenght - 1); //对不等长的两个子表合并
}
tmp = q; q = rf; rf = tmp; //交换q,rf,以保证下一趟归并时,仍从q 归并到rf
}
}
下面附带实现的全部源码。
////////////////////////////////////////////////////////////
//
// SortTest.h
//
////////////////////////////////////////////////////////////
#ifndef __CSORT_TEST_H__
#define __CSORT_TEST_H__
#include
#include
class CSort
{
public:
void swap(int *a,int *b);
//直接插入排序
void InsertSort(int *a, int len);
//希尔排序
void ShellInsert(int *a, int len, int dk/*增量*/);
void ShellSort(int *a,int len);
//快速排序
void QuickSort(int *a,int low,int high);
int Partition(int *a,int low,int high);
//选择排序
void SelectSort(int *a,int len);
//冒泡排序
void BubbleSort(int *a,int len);
//归并排序
void Merge(int *r, int *rf, int i, int m, int n);
void MergeSort(int *r, int *rf, int lenght);
};
#endif
////////////////////////////////////////////////////////////
//
// SortTest.cpp
//
////////////////////////////////////////////////////////////
#include "SortTest.h"
void CSort::swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//直接插入排序
void CSort::InsertSort(int *a, int len)
{
for (int i = 1; i < len; i++)
{
int key = a[i];
int j = i - 1;
while (j>=0 && a[j] > key)
{
a[j + 1] = a[j];
j--;
}
a[j+1] = key;
}
}
//希尔插入,当增量为1时就是直接插入排序
void CSort::ShellInsert(int *a, int len, int dk)
{
for (int i = dk + 1; i < len; i++)
{
int key = a[i];
int j = i - dk;
while (j >= 0 && a[j] > key)
{
a[j +dk] = a[j];
j -= dk;
}
a[j + dk] = key;
}
}
//希尔排序
void CSort::ShellSort(int *a, int len)
{
int k = len / 2;
while (k >= 1)
{
ShellInsert(a, len, k);
k = k / 2;
}
}
//快速排序
int CSort::Partition(int *a, int low, int high)
{
int key = a[low];
while (low < high)
{
while (low < high&&a[high] >= key) high--;
swap(&a[low],&a[high]);
while (low < high&&a[low] <= key) low++;
swap(&a[low],&a[high]);
}
return low;
}
void CSort::QuickSort(int *a, int low, int high)
{
if (low a[j])
{
swap(&a[i], &a[j]);
}
}
}
}
void CSort::Merge(int *r, int *rf, int i, int m, int n)
{
int j, k;
for (j = m + 1, k = i; i <= m && j <= n; ++k){
if (r[j] < r[i]) rf[k] = r[j++];
else rf[k] = r[i++];
}
while (i <= m) rf[k++] = r[i++];
while (j <= n) rf[k++] = r[j++];
}
void CSort::MergeSort(int *r, int *rf, int lenght)
{
int len = 1;
int *q = r;
int *tmp;
while (len < lenght) {
int s = len;
len = 2 * s;
int i = 0;
while (i + len < lenght){
Merge(q, rf, i, i + s - 1, i + len - 1); //对等长的两个子表合并
i = i + len;
}
if (i + s < lenght){
Merge(q, rf, i, i + s - 1, lenght - 1); //对不等长的两个子表合并
}
tmp = q; q = rf; rf = tmp; //交换q,rf,以保证下一趟归并时,仍从q 归并到rf
}
}
int main()
{
CSort sort;
int a[10] = {10,20,32,13,9,25,23,45,56,1};
printf("\n排序前!");
for (size_t i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
//sort.InsertSort(a, 10);
//sort.ShellInsert(a, 10, 1);
//sort.ShellSort(a, 10);
//sort.QuickSort(a, 0, 9);
//sort.SelectSort(a, 10);
//sort.BubbleSort(a, 10);
int b[10] = { 0 };
sort.MergeSort(a,b,10);
printf("\n排序后!");
for (size_t i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("hello world!\n");
system("pause");
return 0;
}