稳定排序口诀:冒泡插入,归并基数,计数桶(除此之外都是不稳定)
一、冒泡排序
稳定排序、时间复杂度 o(n^2) ,空间 o(1)
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
void BubbleSort(int[] a, int n)
{
for (auto i = 0; i < n; ++i)
{
for (int j = 0; j < n - i - 1; ++j)
{
if (a[j] > a[j + 1])
Swap(a[j], a[j + 1]);
}
}
}
二、选择排序
不稳定、时间复杂度:O(n^2),空间O(1)
选择排序是每一趟给每个位置选择当前元素最小的直至最后一个
比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个 元素不用选择了,因为只剩下它一个最大的元素了。
void SelectionSort(int[] a, int n)
{
int minIndex;
for (int i = 0; i < n; ++i)
{
minIndex = i;
for (int j = i + 1; j < n; ++j)
{
if (a[j] < a[minIndex]) minIndex = j;
}
Swap(a[i], a[minIndex]);
}
}
三、插入排序
稳定、时间复杂度 o(n^2) 空间 o(1)
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。
外循环构建有序序列,内循环将有序序列后一位的元素插入有序序列。
刚开始这个有序的小序列只有1个元素,就是第一个元素。每趟比较从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。
void InsertSort(int a[],int l)
{
int temp;
int j;
for(int i=1;i<l;i++)
{
if(a[i]<a[i-1])
{
temp=a[i];
for(j=i-1;j>=0&&temp<a[j];j--)
{
a[j+1]=a[j];
}
a[j+1]=temp;
}
}
}
四、快速排序
不稳定、时间复杂度 o(nlogn) 空间 o(logn)
-
从数列中挑出一个元素,称为 "基准"(pivot);
-
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
-
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
Void QuickSort(vector<int>& nums, int left, int right)
{
int i, j, temp, pivot;
if (left > right)
{
return;
}
pivot = nums[left];
i = left;
j = right;
while (i < j)
{
while (nums[j] >= pivot && i < j)
{
j--;
}
if (i < j)
{
nums[i++] = nums[j];
}
while (nums[i] <= pivot && i < j)
{
i++;
}
if (i < j)
{
nums[j--] = nums[i];
}
}
nums[i] = pivot;
QuickSort(nums, left, i - 1);
QuickSort(nums, i + 1, right);
return;
}
五、归并排序
稳定,时间复杂度 o(nlogn) 空间 o(n)
通过递归的方式将大的数组一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了,之后再把两个数组大小为1的合并成一个大小为2的,再把两个大小为2的合并成4的 … 直到全部小的数组合并起来。
public static List<int> sort(List<int> lst) {
if (lst.Count <= 1)
return lst;
int mid = lst.Count / 2;
List<int> left = new List<int>(); // 定义左侧List
List<int> right = new List<int>(); // 定义右侧List
// 以下兩個循環把 lst 分為左右兩個 List
for (int i = 0; i < mid; i++)
left.Add(lst[i]);
for (int j = mid; j < lst.Count; j++)
right.Add(lst[j]);
left = sort(left);
right = sort(right);
return merge(left, right);
}
// 合併兩個已經排好序的List
static List<int> merge(List<int> left, List<int> right) {
List<int> temp = new List<int>();
while (left.Count > 0 && right.Count > 0) {
if (left[0] <= right[0]) {
temp.Add(left[0]);
left.RemoveAt(0);
} else {
temp.Add(right[0]);
right.RemoveAt(0);
}
}
if (left.Count > 0) {
for (int i = 0; i < left.Count; i++)
temp.Add(left[i]);
}
if (right.Count > 0) {
for (int i = 0; i < right.Count; i++)
temp.Add(right[i]);
}
return temp;
}