1.冒泡排序(时间复杂度O(n^2),空间复杂度O(1),不稳定排序)
首先定义一个变量size_t bount=0
[0,bound)的区间已经排好序的区间,[bound,size)待排序的区间
从第二个数字开始,每一个数字都会和前一个数字进行比较,如符合则交换
void BubbleSort(int array[],size_t size)
{
if (size == 1)
{
return;
}
size_t i = 0;
size_t bound = 0;
for (i = 0; i < size - 1; i++)
{
for (bound = 0; bound < size - 1 - i; bound++)
{
if (array[bound]>array[bound + 1])
{
swap(&array[bound], &array[bound + 1]);
}
}
}
return;
}
2.选择排序(时间复杂度O(n^2),空间复杂度O(1),稳定排序)
void SelectSort(int *array, size_t size)
{
if (size == 1)
{
return;
}
size_t i = 0;
size_t j = 1;
for (i = 0; i < size - 1; i++)
{
for (j = i + 1; j < size; j++)
{
if (array[j] < array[i])
{
swap(&array[i], &array[j]);
}
}
}
return;
}
3.堆排序HeapSort(从小到大,建立大堆)(时间复杂度O(N*logN),空间复杂度O(1),稳定排序)
a.先建一个堆HeapCreate
b.再一个一个的删除堆顶元素
//建立一个大堆,若是从大到小排序的话
void AdjustDown(int array[], size_t size, size_t index)
{
size_t parent = index;
size_t child = parent * 2 + 1;
//从上往下调整
//先找出左右子树中最大的那个,若左比右小,交换
while (child < size)
{
//若有右子树
if (child + 1 < size && array[child] < array[child + 1])
{
child = child + 1;
}
if (array[child] > array[parent])
{
swap(&array[child], &array[parent]);
}
else
{
break;
}
parent = child;
child = parent * 2 + 1;
}
return;
}
void HeapPop(int array[], size_t size)
{
swap(&array[0], &array[size - 1]);
--size;
AdjustDown(array, size, 0);
}
void HeapCreate(int array[], size_t size)
{
if (array == NULL)
{
return;
}
//算出最后一个节点的父节点的下标从这开始调整
size_t i = (size - 1 - 1) / 2;
for (; i > 0; --i)
{
AdjustDown(array, size, i);
}
AdjustDown(array, size, 0);
}
//堆排序
void HeapSort(int array[], int size)
{
//只有一个数字不用排序
if (size == 1)
{
return;
}
//构建一个大堆
HeapCreate(array, size);
size_t i = 0;
//
for (; i < size - 1; ++i)
{
//一个一个删除堆顶元素
HeapPop(array, size - i);
}
return;
}
4.插入排序(时间复杂度(O(N^2)),空间复杂度(N(1),稳定排序)
[0,bound)的区间已经排好序的区间,[bound,size)待排序的区间
每次取到一个元素就将它插入到已经排好的区间中(即线性表的插入,搬运)
//从小到大排序
void InsertSort(int array[], size_t size)
{
if (array == NULL || size <= 1)
{
return;
}
size_t bound = 1;
for (; bound < size; ++bound)
{
int value = array[bound];
size_t i = bound;
for (; i>0; --i)
{
//因为前面已经有序,现在就是判断它需不需要搬运就是调整
if (array[i-1] > value)
{
array[i] = array[i - 1];
}
else
{
break;
}
}
array[i] = value;
}
return;
}
5.希尔(shell)排序(时间复杂度(O(N^2)))
就是将数据根据步长分为若干组
步长为4(分为2组)
将第一个组的第一个元素和第二个组的第一个元素比较若大,则交换,然后会第一个组的第二个元素和第二组的第二个元素…
步长为2(分为四组)
依旧进行比较
画一画就明白了
void ShellSort(int array[], size_t size)
{
if (size <= 1)
{
return;
}
//先生成步长序列
size_t gap = size / 2;
for (; gap > 0; gap /= 2)
{
size_t bound = gap;
for (; bound < size;bound++)
{
size_t i = bound;
for (; i>gap; i -= gap)
{
if (array[i - gap] > array[i])
{
swap(&array[i], &array[i - gap]);
}
}
}
}
}
对于插入排序来说如果序列已经基本有序,那么插入排序的速度非常快
如果元素个数肥肠少,那么插入排序的速度也非常快
6归并排序
先划分子区间,然后在两个两个区间的有序合并
递归版本(其实就是划分区间部分需要递归)
非递归版本(手动划分区间)
void _MergeArray(int array[], size_t beg, size_t mid, size_t end, int *tmp)
{
size_t cur1 = beg;
size_t cur2 = mid;
size_t tmp_index = beg;
while (cur1 < mid&&cur2 < end)
{
//将这两个区间里较小的数放入一个新开辟的空间里
if (array[cur1] < array[cur2])
{
tmp[tmp_index++] = array[cur1++];
}
else
{
tmp[tmp_index++] = array[cur2++];
}
}
//处理一个完了另外一个剩下的情况,下面这两个只有一个生效
while (cur1 < mid)
{
tmp[tmp_index++] = array[cur1++];
}
while (cur2 < end)
{
tmp[tmp_index++] = array[cur2++];
}
//将tmp里的元素拷回到array里
//从那开始,从哪结束,拷贝多少个字节
memcpy(array + beg, tmp + beg, sizeof(int)*(end - beg));
}
//递归版本
void _MergeSort(int array[], size_t beg, size_t end, int *tmp)
{
if (end - beg <= 1)
{
return;
}
//先划分有序区间
size_t mid = beg + (end - beg) / 2;
//递归的划分子区间
_MergeSort(array, beg, mid, tmp);
_MergeSort(array, mid, end, tmp);
//要先保证左右区间为有序之后才能进行合并
_MergeArray(array, beg, mid, end, tmp);
}
void MergeSort(int array[], size_t size)
{
if (size <= 1)
{
return;
}
int *tmp = (int *)malloc(sizeof(int)*size);
_MergeSort(array, 0, size, tmp);
free(tmp);
}
//非递归版本
//其实就是手动的划分子区间
void MergeSortByLoop(int array[], size_t size)
{
if (size <= 1)
{
return;
}
int *tmp = (int *)malloc(sizeof(int)*size);
//先划分区间,再有序合并
//此为手动划分区间部分
size_t gap = 1;
for (; gap < size; gap *= 2)
{
//进行有序合并
size_t i = 0;
for (; i < size; i += 2 * gap)
{
int beg = i;//区间开始
int mid = i+gap;//第二个区间的开始
int end = i + gap * 2;//总处理区间的结束
if (mid>size)
{
mid = size;
}
if (end > size)
{
end = size;
}
_MergeArray(array, beg, mid, end, tmp);
}
}
}
7.快速排序
定义一个标杆一般是数组最后一个元素
定义两个left,right指针,分别指向数组第一个元素和最后一个元素,left向后走,right向前走,当left指针指向第一个比标杆大的元素,right指向读一个比标杆小的元素,则交换这两个指针所代表的元素,直到这两个指针重合,则将这个指针和标杆元素交换,此时标杆左边都是比它小的元素,标杆元素右边都是比它大的元素,然后在对这两边的数组在分别进行排序
//交换法
int Partion1(int array[], size_t beg, size_t end)
{
size_t left = beg;
size_t right = end - 1;//最后一个元素
int key = array[right];
while (left < right)
{
//不对
/*while (array[left++] <= key&&array[right--] >= key&&left < right)
{
swap(&array[left], &array[right]);
}*/
while (left<right&&array[left]<=key)
{
++left;
}
while (left<right&&array[right]>=key)
{
--right;
}
if (left < right)
{
swap(&array[left], &array[right]);
}
}
//交换基准值和此时的left指针
swap(&array[left], &array[end - 1]);
return left;
}
//挖坑法
int Partion2(int array[], size_t beg, size_t end)
{
size_t left = beg;
size_t right = end - 1;
int key = array[right];
while (left<right)
{
//从左到右先找到一个大于基准值的元素
while (left < right&&array[left] <= key)
{
left++;
}
if (left < right)
{
//将找到的这个left值填到right里
array[right--] = array[left];
}
//从右往左找倒一个小于基准值的元素
while (left < right&&array[right] >= key)
{
--right;
}
if (left < right)
{
array[left++] = array[right];
}
}
array[left] = key;
return left;
}
void _QuickSort(int array[], size_t beg, size_t end)
{
if (end - beg <= 1)
{
return;
}
//Partion函数的作用是对当前的[beg,end)区间进行整理
//整理成以某个基准值为中心,左边都比它小,右边都比它
//返回值hi返回基准值所在下标
int mid = Partion1(array, beg, end);
Partion1(array, beg, mid);
Partion1(array, mid, end);
}
//快速排序
void QuickSort(int array[], size_t size)
{
if (size <= 1)
{
return;
}
_QuickSort(array, 0, size);
}