排序算法
较慢算法
-
冒泡排序
实现:
void BubbleSort(int* a, int n) { for (int i = 0; i < n - 1; i++) { int flag = 1; for (int j = 0; j < n - i - 1; j++) { if (a[j] < a[j + 1]) { swap(&a[j], &a[j + 1]); flag = 0; } } if (flag)break; } }
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性分析:由于只有相邻两个数之间存在交换,只有需要变动位置的数的相对位置会改变。
-
选择排序
思路:遍历找到最大或者最小的值,放到第一位,找到第二大的,放到第二位,以此类推
void SelectSort(int* a, int n) { int begin = 0, end = n - 1; while (begin < end) { int mini = begin, maxi = begin; for (int i = begin+1; i <= end; i++) { if (a[mini] > a[i]) { mini = i; } if (a[maxi] < a[i]) { maxi = i; } } swap(&a[mini],&a[begin]); if (maxi == begin)maxi = mini; swap(&a[end] , &a[maxi]); begin++; end--; } }
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:在存在相等的数据下,由于交换操作,会将已排序好的数据变换,因此并不稳定
-
插入排序
思路:将数组分为有序区和无序区,从无序区中拿数插入到有序区中。
实现:
void InsertSort(int* a, int n) { for (int i = 0; i < n - 1; ++i) { int end = i; int tmp = a[end + 1]; while (end >= 0) { if (tmp < a[end]) { a[end + 1] = a[end]; end--; } else { break; } } a[end + 1] = tmp; } }
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:只是插入而并不造成其他元素相对位置的变化,因此是稳定的
较快排序
-
堆排序
思路:建立堆,将堆的的根节点和最后一个节点进行交换,之后再次建立一个更小的堆
实现:
void AdjustDwon(int* a, int n, int root) { int child = root * 2 + 1; while (child < n) { if (a[child] < a[child + 1] && child + 1 < n) { child++; } if (a[root] < a[child]) { swap(&a[root], &a[child]); root = child; child = root * 2 + 1; } else { break; } } } void HeapSort(int* a, int n) { for (int i = (n - 1 - 1) / 2; i >= 0; i--) { AdjustDwon(a, n, i); } int end = n - 1; while (end > 0) { swap(a[0], a[end]); AdjustDwon(a, end, 0); end--; } }
时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:由于不断地交换以及建堆可能会造成原本顺序的变化,因此不稳定
2.快速排序
实现
int getmidi(int* a, int left,int right) { int midi = (left + right) / 2; if (a[left] > a[midi]) { if (a[midi] > a[right])return midi; else if (a[left] < a[right]) return left; else return right; } else { if (a[midi] < a[right])return midi; else if (a[left] > a[right])return left; else return right; } } int PartSort1(int* a, int left, int right) { int begin = left, end = right; int keyi = getmidi(a,left,right); while (begin < end) { while (begin < end && a[end]>=a[keyi]) { end--; } while (begin < end && a[begin] <= a[keyi]) { begin++; } swap(&a[begin], &a[end]); } swap(&a[keyi], &a[begin]); keyi = begin; return keyi; } void QuickSort(int* a, int left, int right) { if (left >= right)return; if ((right - left + 1) < 10) { InsertSort(a + left, right - left + 1); } else { int keyi = PartSort1(a, left, right); QuickSort(a, left, keyi - 1); QuickSort(a, keyi + 1, right); } }
时间复杂度:O(nlogn)
空间复杂度:O(logn)
稳定性:显然,存在交换,于是使得快排分区发生了变化,进而影响了已稳定的元素,造成不稳定
3.归并排序
思路:通过不断的二分分隔,直到每组只包含一个元素,达成有序,再将每组的元素进行合并,达成每组的有序
实现:
void MergeSort(int* a, int n) { int* tmp = (int*)malloc(sizeof(int) * n); if (tmp == NULL) { printf("malloc fail\n"); return; } _MergeSort(a, tmp, 0, n - 1); free(tmp); tmp = NULL; } void _MergeSort(int* a, int *tmp, int begin, int end) { if (begin == end)return; int mid = (begin + end) / 2; _MergeSort(a, tmp, begin, mid); _MergeSort(a, tmp,mid + 1, end); int begin1 = begin, end1 = mid; int begin2 = mid + 1, end2 = end; int i = begin; while (begin1 <= end1 && begin2 <= end2 ) { if (a[begin1] < a[begin2]) tmp[i++] = a[begin1++]; else tmp[i++] = a[begin2++]; } while (begin1 <= end1) { tmp[i++] = a[begin1++]; } while (begin2 <= end2) { tmp[i++] = a[begin2++]; } memcpy(a + begin, tmp + begin, (end - begin + 1)*sizeof(int)); }
时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:由于在归并时,相同的元素会优先选择左边的元素,即保持了原顺序的相对不变
4.希尔排序:
思路:在插入排序的基础上,进行预排序,将数据分组,对每组进行插入排序,最后进行总插入排序
实现:
void ShellSort(int* a, int n) { int gap = n; while (gap > 1) { gap = gap / 3 + 1; for (int i = 0; i < n - gap; i += gap) { int end = i; int tmp = a[end + gap]; while (end >= 0) { if (tmp < a[end]) { a[end + gap] = a[end]; end -= gap; } else { break; } } a[end+gap] = tmp; } } }
时间复杂度:O(n^1.3)
空间复杂度:O(1)
稳定性:由于分组时可能会将相同的元素分到不同的组,导致相对顺序发生变化,因此不稳定
-