一、排序
在生活中各种场景中都会有排序的身影存在,在网购时会有价格排序,在学校中会有程序排序,在游戏中会有段位的排序等。
1、排序的各种方式分类
这些排序的效率各有不同
二、插入排序
直接插⼊排序是⼀种简单的插⼊排序法,其基本思想是:把待排序的记录按其关键码值的⼤⼩逐个插⼊到⼀个已经排好序的有序序列中,直到所有的记录插⼊完为⽌,得到⼀个新的有序序列 。
1、直接插入排序
当插⼊第 i(i>=1) 个元素时,前⾯的 array[0],array[1],…,array[i-1] 已经排好序,此时⽤ array[i] 的排序码与 array[i-1],array[i-2],… 的排序码顺序进⾏⽐较,找到插⼊位置即将 array[i] 插⼊,原来位置上的元素顺序后移
代码实现:
void InsertionSort(int* arr, int n)
{
int i = 0;
int j = 0;
for ( i = 1; i < n; i++)
{
j = i-1;
int tmp = arr[i];
while (j >= 0)
{
if (arr[j] < tmp)
{
arr[j + 1] = arr[j];
j--;
}
else
{
break;
}
}
arr[j + 1] = tmp;
}
}
2、希尔排序
直接插入排序效率不高,在直接插入排序的基础上进行优化,改进,把一个大的集合分为若干个小的集合再进行直接插入排序,从而提升效率。
希尔排序法⼜称缩⼩增量法。希尔排序法的基本思想是:先选定⼀个整数(通常是gap = n/3+1),把待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,当gap=1时,就相当于直接插⼊排序。
代码实现:
void ShellSort(int* arr, int n)
{
int gec = n;
int i, j = 0;
while (gec > 1)
{
gec = gec / 3 + 1;
for (i = gec; i < n; i++)
{
j = i - gec;
int tmp = arr[i];
while (j >= 0)
{
if (arr[j] < tmp)
{
arr[j + gec] = arr[j];
j -= gec;
}
else
{
break;
}
}
arr[j + gec] = tmp;
}
}
}
3、希尔排序时间复杂度分析
外层循环的时间复杂度可以直接给出为: O(log2 n) 或者 O(log3 n) ,即 O(log n)
内层循环:
希尔排序的时间复杂度大约为 log 2 n 1.3 \log_2 {n^{1.3}} log2n1.3
三、选择排序
每⼀次从待排序的数据元素中选出最⼩(或最⼤)的⼀个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
1、直接选择排序
void SelectSort(int* a, int n)
{
int begin = 0, end = n - 1;
while (begin < end)
{
int max = begin, min = begin;
for (int i = begin + 1; i <= end; i++)
{
if (a[i] < a[min])
{
min = i;
}
if (a[i] > a[max])
{
max = i;
}
}
if (max == begin)
{
max = min;
}
{
int tmp = a[min];
a[min] = a[begin];
a[begin] = tmp;
}
{
int tmp = a[max];
a[max] = a[end];
a[end] = tmp;
}
begin++;
end--;
}
}
2、堆排序
void HeapSort(int* arr, int n)
{
int i = 0;
for (i = (n-1)/2; i>=0; i--)
{
int parent = i;
int child = parent * 2 + 1;
while (child <= i)
{
if (child + 1 <= i && arr[child + 1] < arr[child])
{
child++;
}
if (arr[child] < arr[parent])
{
int tmp = arr[parent];
arr[parent] = arr[child];
arr[child] = tmp;
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
for (i = n - 1; i > 0; i--)
{
int child = i;
int parent = 0;
int tmp = arr[parent];
arr[parent] = arr[child];
arr[child] = tmp;
child = parent * 2 + 1;
while (child < i)
{
if (child + 1 < i && arr[child + 1] < arr[child])
{
child++;
}
if (arr[child] < arr[parent])
{
tmp = arr[parent];
arr[parent] = arr[child];
arr[child] = tmp;
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
}
堆排序的时间复杂度为n log n \log n logn
四、交换排序
1、冒泡排序
void BubbleSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int falg = 1;
for (int j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[j + 1])
{
int tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
falg = 0;
}
}
if (falg)
{
break;
}
}
}
2、快速排序
通过找基准值,基准值的位置就是这个值该待的位置,然后递归找基准值左边区间和右区间,直到区间不成立位置,确定每个值该待的位置完成排序。
int _QuickSort(int* a, int left, int right)
{
int keyi = left;
left++;
while (left <= right)
{
while (left <= right && a[left] < a[keyi])
{
left++;
}
while (left <= right && a[right] > a[keyi])
{
right--;
}
if (left <= right)
{
int tmp = a[left];
a[left] = a[right];
a[right] = tmp;
left++;
right--;
}
}
int tmp = a[keyi];
a[keyi] = a[right];
a[right] = tmp;
return right;
}
void QuickSort(int* a, int left,int right)
{
if (left >= right)
{
return;
}
int keyi = _QuickSort(a, left, right);
QuickSort(a, keyi + 1, right);
QuickSort(a, left, keyi - 1);
}
快排的空间复杂度:O( l o n g n long n longn)
快排的时间复杂度:O(n l o n g n long n longn)