排序的相关概念:
什么是排序,排序的稳定性,内部排序与外部排序 ?
排序:就是使一串记录,照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。(即排序过程前后不改变两个相同元素的相对位置)
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。
插入、希尔、选择、堆排、冒泡、归并、快速、计数排序
插入、希尔、选择、堆排、冒泡、归并、快速是七种基于比较的排序
计数排序是非比较排序
直接插入排序
排序原理
如图,在无序队列中取第一个数按照一定顺序插入到有序队列中,无序队列范围每进行一次循环便会减一,剩余无序队列按照相同方法继续进行下去,是减治算法
1)找到要插入的下标
2)插入值
代码实现
void insertSort(int array[], int size){
for (int i = 0; i < size; i++)
{
int k = array[i];
int j;
for (j = i - 1; j >= 0 && k < array[j]; j--)
{
array[j + 1] = array[j];
}
array[j + 1] = k;
}
}
稳定性
稳定
时间空间复杂度
时间复杂度
最优:O(n)
最坏(平均):O(n^2)
空间复杂度:O(1)
希尔排序
排序原理
分组进行插入排序,
前提:在插入排序中,数据中越有序排序的效率越高。
其中间隔gap=gap/3-1或gap=gap/2
代码实现
void insertSortWithgap(int array[], int size, int gap){
{
for (int i = 0; i < size; i++)
{
int k = array[i];
int j;
for (j = i - gap; j >= 0 && k < array[j]; j-=gap)
{
array[j + gap] = array[j];
}
array[j + gap] = k;
}
}
}
void shellSort(int array[], int size){
int gap = size;
while (1){
gap = gap / 2;
insertSortWithgap(array, size, gap);
if (gap == 1)
break;
}
}
稳定性
不稳定
时间空间复杂度
平均时间复杂度:O(N1.3—N2)
选择排序
排序原理
在无序范围数据中找到最大值放在最右边(或最左边),是减治算法。
可选最大放后面/选最小放前面/选最大、最小放后面、前面
代码实现
void selectSort(int array[], int size){
for (int i = 0; i < size; i++)
{
int max = 0;
for (int j = 0; j < size - i; j++)
{
if (array[j]>array[max])
max = j;
}
swap(array + max, array + size - i - 1);//在之前的冒泡排序中定义
}
}
稳定性
不稳定
时间空间复杂度
时间复杂度:O(n)
空间复杂度:O(1)
堆排序
排序原理
1.建大堆(降序建小堆)
2.堆顶元素(最大)和无需区间最后一个数进行交换
3.对堆进行向下调整
只能选最大放后面
代码实现
void heapajust(int arr[], int start, int end) {
int dad = start;
int son = dad * 2 + 1;
while (son <= end) {
if (son + 1 <= end && arr[son] < arr[son + 1])
son++;
if (arr[dad] > arr[son])
return;
else {
swap(&arr[dad],&arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
void heapSort(int arr[], int len) {
int i;
for (i = len / 2 - 1; i >= 0; i--) {
heapajust(arr, i, len - 1);
}
for (i = len - 1; i > 0; --i) {
swap(arr+0, arr+i);
heapajust(arr, 0, i - 1);
}
}
时间空间复杂度
时间复杂度:O(N*logN)
空间复杂度:O(1)
冒泡排序
排序原理
两数比较判断是否需要交换,每趟交换完成得到无序元素中最大数
代码实现
void swap(int* a, int* b){
int temp = *a;
*a = *b;
*b = temp;
}
//一个函数要修改另外一个函数的数据,必须传指针和解引用
void bubbleSort(int array[], int size){
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size - i - 1; j++)
{
if (array[j]>array[j+1])
swap(array+j, array+j+1);
}
}
}
稳定
时间空间复杂度
时间复杂度:O(n^2)
空间复杂度:O(1)
归并(合并)排序
排序原理
1.把整个待排序区间平均分成两份
2.分别对左右两个小区间按照分治算法处理,知道小区间内个数<=1。
3.合并两个有序区间
void Merge(int *a, int begin1, int end1, int begin2, int end2, int *tmp)
{
int index = begin1;
int i = begin1, j = begin2;
while (i <= end1&&j <= end2){
if (a[i] <= a[j])
tmp[index++] = a[i++];
else
tmp[index++] = a[j++];
}
while (i <= end1)
tmp[index++] = a[i++];
while (j <= end2)
tmp[index++] = a[j++];
memcpy(a + begin1, tmp + begin1, sizeof(int)*(end2 - begin1 + 1));
}
void MergeSort(int *a, int left, int right, int *tmp)
{
if (left >= right)
return;
assert(a);
int mid = left + ((right - left) >> 1);
MergeSort(a, left, mid, tmp);
MergeSort(a, mid + 1, right, tmp);
Merge(a, left, mid, mid + 1, right, tmp);
}
稳定性
稳定
时间空间复杂度
时间复杂度:O(N*logN)
空间复杂度:O(N)
应用场景
解决磁盘中的外排序问题。
快速排序
排序原理
分治算法
1.在待排区间[left,right]中选择一个基准值(pivot)
1)选边上的值
2)随机选值
3)三数取中间值
2.扫描整个待排区间,比基准值小的放在基准值左边,比基准值大的放在基准值右边。
分组(parition)
1)Hover法
2)挖坑法
相较hover法而言是将right保存而非交换
3)前后下标
3.整个待排区间分为三个部分:
比基准值小的[left,pivotIndex+1]
基准值[pivotIndex]
比基准值大的[pivotIndex+1,right]
照样处理左右两个区间,直到区间内数据个数为1或0。
代码实现
int quickSort(int a[], int p, int q)
{
int i, j;
int max, n;
n = q - p + 1;
if (p >= q)
{
return 0;
}
else
{
max = a[p];
j = p;
for (i = p + 1; i <= q; i++)
{
if (max >= a[i])
{
n = a[i];
a[i] = a[j + 1];
a[j + 1] = n;
n = a[j];
a[j] = a[j + 1];
a[j + 1] = n;
j = j + 1;
}
}
quickSort(a, p, j - 1);
quickSort(a, j + 1, q);
}
return 0;
}
稳定性
不稳定
时间空间复杂度
时间复杂度:O(N*logN)
空间复杂度:O(logN)
计数排序
排序原理
1.统计每个数出现的次数
2.数据回收
代码实现
void countSort(int *arr, int size)
{
int i;
int minValue = arr[0];
int maxValue = arr[0];
int range = 0;
int* tmp = 0;
int count = 0;
for (i = 0; i < size; i++)
{
if (arr[i] < minValue){
minValue = arr[i];
}
if (arr[i] > maxValue){
maxValue = arr[i];
}
}
range = maxValue - minValue + 1;
tmp = (int*)malloc(sizeof(arr[0])*size);
if (tmp == NULL)
return;
memset(tmp, 0, sizeof(int)*range);
for (i = 0; i < size; i++)
{
tmp[arr[i] - minValue]++;
}
for (i = 0; i<range; i++)
{
while (tmp[i]--)
{
arr[count++] = i + minValue;
}
}
free(tmp);
}
稳定性
稳定
时间空间复杂度
时间复杂度:O(MAX(N,范围))
空间复杂度:O(范围)
应用场景
数据密集的集中在某一范围内