排序
各种排序方法时间复杂度、空间复杂度对比
其中“稳定”是指相对次序不会发生改变
最好 | 平均 | 最坏 | 空间 | ||
---|---|---|---|---|---|
直接插入排序 | |||||
折半插入排序 | |||||
希尔排序 | |||||
冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
快速排序 | |||||
简单选择排序 | |||||
堆排序 | |||||
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
一、插入排序
1、直接插入排序
2、折半插入排序
3、希尔排序
二、交换排序
1、冒泡排序
代码:
void sort(vector<int> &array){
int n = array.size();
for(int i=0; i<n-1; i++){
bool flag = false;
for(int j=n-1; j>i; j--){
swap(array[j], array[j-1]);
flag = true;
}
if(!flag) break; //一遍冒泡后没有元素交换位置,说明array已经是有序数组,直接退出
}
}
2、快速排序
三、选择排序
1、简单选择排序
2、堆排序
四、归并排序
- 概念:
- 归并排序是多次将两个或两个以上的有序表合并成一个新的有序表。
- 二路归并排序:直接将两个有序的子表合并成一个有序的表。
- 基本思路: 将R[0…n-1]看成是n个长度为1的有序序列,然后进行两两归并,得到n/2向上取整个长度为2(最后一个有序序列的长度可能为2)的有序序列,再进行两两归并,得到n/4向上取整个长度为4(最后一个有序序列的长度可能小于4)的有序序列……,直到得到一个长度为n的有序序列
- 归并排序每趟产生的有序区只是局部有序的,也就是说在会后一趟排序结束前所有元素并不一定归位了。
- 时间复杂度:O(nlogn),二路归并logn向上取整趟,每趟归并时间为O(n)
- 空间复杂度O(n)
Merge()实现一次归并:
void Merge(int low, int mid,int high, vector<int> &array){
int i=low, j=mid+1;
vector<int> tmp;
while(i<=mid && j<=high){
if(array[i] < array[j])
tmp.push_back(array[i++]);
else
tmp.push_back(array[j++]);
}
while(i<=mid)
tmp.push_back(array[i++]);
while(j<=high)
tmp.push_back(array[j++]);
for(int k=0, i=low; i<=high; i++, k++){
array[i] = tmp[k];
}
}
自底向上:
//自底向上
void MergeSort(vector<int>& array){
int n = array.size();
for(int length=1; length<n; length*=2){ //进行ogn向上取整,趟归并
//对整个排序序列进行一趟归并
//在调用Merge()将相邻的一对子表进行归并时,
//需要对表的个数可能是奇数以及最后一个子表的长度小于length这两种特殊情况进行特殊处理;
//若子表个数为奇数,则最后一个子表无须和其他子表归并(本趟轮空);
// 若子表个数为偶数,则要注意到最后一对子表中后一个子表的区间上界是n-1。
int i;
for(i=0; i+2*length-1<n; i+=2*length){ //归并length长的两相邻子表
Merge(i, i+length-1, i+2*length-1, array);
}
if(i+length-1 < n-1){ //偶数,余下两个子表,后者的长度小于length
Merge(i, i+length-1, n-1, array); //归并这两个子表
}
}
}
自顶向下:
//自顶向下
void MergeSort(int low, int high,vector<int> &array){
if(low<high){
int mid = low +((high-low)>>1);
MergeSort(low, mid, array);
MergeSort(mid+1, high, array);
Merge(low, mid, high, array);
}
}
例题
1、NC140 排序【字节跳动、百度、阿里巴巴、度小满】
题解:归并排序
时间复杂度:O(nlogn)。二路归并logn向上取整趟,每趟归并时间为O(n)
空间复杂度:O(n)
自底向上
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型vector 待排序的数组
* @return int整型vector
*/
void merge(int low, int mid, int high, vector<int> &arr){
int i = low, j = mid+1;
vector<int> tmp;
while(i <= mid && j <= high){
if(arr[i] <= arr[j]) tmp.push_back(arr[i++]);
else tmp.push_back(arr[j++]);
}
while(i <= mid){
tmp.push_back(arr[i++]);
}
while(j <= high){
tmp.push_back(arr[j++]);
}
for(int k = 0, i = low; k<tmp.size(); k++, i++){
arr[i] = tmp[k];
}
}
vector<int> MySort(vector<int>& arr) {
// write code here
int n = arr.size();
for(int length = 1; length < n; length *= 2){
int i;
for(i=0; i+2*length-1 < n; i+=2*length){
merge(i, i+length-1, i+2*length-1, arr);
}
if(i<n){
merge(i, i+length-1, n-1, arr);
}
}
return arr;
}
};
自顶向下
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型vector 待排序的数组
* @return int整型vector
*/
void merge(int low, int mid, int high, vector<int> &arr){
int i = low, j = mid+1;
vector<int> tmp;
while(i <= mid && j <= high){
if(arr[i] <= arr[j]) tmp.push_back(arr[i++]);
else tmp.push_back(arr[j++]);
}
while(i <= mid){
tmp.push_back(arr[i++]);
}
while(j <= high){
tmp.push_back(arr[j++]);
}
for(int k = 0, i = low; k<tmp.size(); k++, i++){
arr[i] = tmp[k];
}
}
void sort(int low, int high, vector<int> &arr){
if(low < high){
int mid = low + ((high - low)>>1);
sort(low, mid, arr);
sort(mid+1, high, arr);
merge(low, mid, high, arr);
}
}
vector<int> MySort(vector<int>& arr) {
// write code here
sort(0, arr.size()-1, arr);
return arr;
}
};