一.常见排序算法
插入排序 1.直接插入排序 2.希尔排序
选择排序 3.选择排序 4.堆排序
交换排序 5.冒泡排序 6.快速排序
归并排序 7.归并排序
二.插入排序
1.直接插入排序
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:稳定
算法描述:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
void strinsert(int *a, int size) {
for (int i = 1; i < size; i++) {
if (a[i] < a[i - 1]) { // 如果当前数比前一个数小
int cur = a[i]; // 把当前数记录下来
int j = i - 1; // 用j来记录当前数的前一个数的下标
for (; j >= 0 && cur < a[j]; j--) {
a[j + 1] = a[j];
}
a[++j] = cur; // j要记得++
}
}
}
1.希尔排序
时间复杂度:O(N^1.3) - O(N^2)
空间复杂度:O(1)
稳定性:不稳定
算法描述:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
void shell(int *a, int size, int d)
{
int i, j, tmp;
for (i = d; i < size; ++i)//这里参照直接插入排序
{
tmp = a[i];
for (j = i - d; j >= 0 && a[j] > tmp; j = j - d)
{
a[j + d] = a[j];
}
a[j + d] = tmp;
}
}
void shellSort(int *a, int size)
{
for (int i = size/2; i >=1; i=i/2)
{
shell(a,size,i);
}
}
三.选择排序
1.选择排序
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:不稳定
算法描述:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
void ssort(int* a, int size) {
int i, j, min;
for (i = 0; i < size; i++) {
min = i;
for (j = i + 1; j < size; j++) {
if (a[j] < a[min]) {
min = j;
}
}
if (a[i] != a[min]) {
swap(a[i],a[min]);
}
}
2.堆排序
时间复杂度:O(N*logN)
空间复杂度:O(1)
稳定性:不稳定
算法描述:利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
void sift_down(int a[], int s, int n)
{
int child = 2 * s;
int index;
while (child <= n)
{
if (child + 1 <= n)
a[child] > a[child + 1] ? index = child : index = child + 1;
else
index = child;
if (a[s] < a[index])
{
swap(a[s], a[index]);
if (index == child) /*********重要!!!********/
s = child;
else
s = child + 1;
child = 2 * s;
}
else
return;
}
}
void heapSort(int a[], int n)
{
int i;
for (i = n; i >= 1; i--)
{
swap(a[1], a[i]);
sift_down(a, 1, i - 1);
}
}
四.交换排序
1.冒泡排序
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:稳定
算法描述:它循环走过需要排序的元素,依次比较相邻的两个元素,如果顺序错误就交换,直至没有元素交换,完成排序。若对n个人进行排序,我们需要n-1次比较,所以第k次比较需要进行n-k次比较。
void msort(int* a,int size) {
int i, j,flag;
for (i = 0; i < size; i++) {
flag = 0;
for (j = 0; j < size - i-1; j++) {
if (a[j] > a[j + 1]) {
swap(a[j], a[j + 1]);
flag++;
}
}
if (flag == 0)break;
}
}
2.快速排序
时间复杂度:O(NlogN)
空间复杂度:O(1)
稳定性:不稳定
算法描述:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
一般情况下,快排遇到的都是o(NlogN),最坏情况为O(N^2),一般不考虑。优先使用快排!
int Partation(int a[], int left, int right)
{
int key = a[left];
while (left < right)
{
while (left < right&&a[right] >= key)
{
right--;
}
a[left] = a[right];
while (left < right&&a[left] <= key)
{
left++;
}
a[right] = a[left];
}
a[left] = key;
return left;
}
void QuickSort(int a[], int left, int right)
{
if (left < right) {
int middle = Partation(a, left, right);
QuickSort(a, left, middle - 1);
QuickSort(a, middle + 1, right);
}
}
五.归并排序
1.归并排序
时间复杂度:O(N*logN)
空间复杂度:O(N)
稳定性:稳定
算法描述:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
int L[1000], R[1000];
int cnt=0;
void merge(int *a, int left, int mid, int right) {
int n1 = mid - left;
int n2 = right - mid;
for (int i = 0; i < n1; i++) L[i] = a[left + i];
for (int i = 0; i < n2; i++) R[i] = a[mid + i];
L[n1] = R[n2] = 1000000;
int i = 0, j = 0;
for (int k = left; k < right; k++) {
cnt++;
if (L[i] <= R[j]) {
a[k] = L[i++];
}
else {
a[k] = R[j++];
}
}
}
void mergeSort(int *a, int left, int right) {
if (left + 1 < right) {
int mid = (left + right) / 2;
mergeSort(a, left, mid);
mergeSort(a, mid, right);
merge(a, left, mid, right);
}
}