8大排序算法的详解

大纲

在这里插入图片描述

复杂度

排序名最优时间复杂度最坏时间复杂度平均时间复杂度空间复杂度稳定性复杂性
插入排序O(n)O(n2)O(n2)O(1)稳定简单
冒泡排序O(n)O(n2)O(n2)O(1)稳定简单
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定较复杂
计数排序O(n )O(n + K)O(n + k)O(K)稳定简单
桶排序O(n)O(n2)O(n + C)O(n + m)稳定较复杂
选择排序O(n2)O(n2)O(n2)O(1)不稳定简单
快速排序O(nlogn)O(n2)O(nlogn)O(nlogn)不稳定较复杂
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定较复杂
希尔排序O(n)O(n2)O(nlogn)O(1)不稳定较复杂

注:C=N*(logN-logM), n个数据,m个桶

O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n)

稳定排序:

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

我都可以代码实现询问面试官哪个算法需要展开?

计数排序

#include<iostream>
using namespace std;
  
const int MAX_N = 100000;
int nums[MAX_N + 5];
int temp[MAX_N + 5];
int res[MAX_N + 5];

void CourtSort(int *nums, int *temp, int k, int n) {
    for (int i = 1; i <= k; ++i) {
        temp[i] += temp[i - 1];
    }
    for (int i = n - 1; i >= 0; --i) {
        res[--temp[nums[i]]] = nums[i];
    }
    return ;
}


int main() {
    int n;
    cin >> n;
    int k = 0;
    for (int i = 0; i < n; ++i) {
        cin >> nums[i];
        k = max(k, nums[i]);
        ++temp[nums[i]];
    }
    CourtSort(nums, temp, k, n);
    for (int i = 0; i < n; ++i) {
        cout << res[i] << endl;
    }
    return 0;
}

归并排序

#define swap(a, b) {\
    __typeof(a) __temp = (a);\
    (a) = (b), (b) = __temp;\
}
void merge_sort(int *data, int l, int r) {
	if(r - l <= 1) {
        if (r - l == 1 && data[l] > data[r]) {            
			swap(data[l], data[r]);
        }        
        return ;
    }    
    int mid = (l + r) >> 1;
    merge_sort(data, l, mid);
    merge_sort(data, mid + 1, r);
    int *temp = (int *)malloc(sizeof(int) * (r - l + 1));    
    int x = l, y = mid + 1, loc = 0;
    while (x <= mid || y <= r) {        
    	if (x <= mid && (y > r || data[x] <= data[y])) {
    		temp[loc++] = data[x++];        
    	} else {
    		temp[loc++] = data[y++]; 
    	}
    }    
    memcpy(data + l, temp, sizeof(int) * (r - l + 1));
    free(temp);}

插入排序

#define swap(a, b) {\
    __typeof(a) __temp = (a);\
    (a) = (b), (b) = __temp;\
}
void insert_sort(int *data, int n) {
    for (int i = 1; i < n; i++) {
    	for (int j = i; j > 0 && (data[j] < data[j - 1]); j--) {            
            swap(data[j], data[j - 1]);
        }   
    }
    return ;
}

冒泡排序

#define swap(a, b) {\
    __typeof(a) __temp = (a);\    
    (a) = (b), (b) = __temp;\
}
void bubble_sort (int *data, int n) {    
	int times = 1;
    for (int i = n - 1; i >= 1 && times; i--) {    
        times = 0;
        for (int j = 0; j < i; j++) {      
              if (data[j] <= data[j + 1]) continue;
              swap(data[j], data[j + 1]);     
              times += 1;
        }  
    }
    return ;
}

选择排序

#define swap(a, b) {\
    __typeof(a) __temp = (a);\ 
    (a) = (b), (b) = __temp;\
}
void select_sort(int *num, int n) {
    for (int i = 0; i < n - 1; i++) {
        int ind = i;        
        for (int j = i + 1; j < n; j++)  {
            if (num[ind] > num[j]) ind = j;
        }
        swap(num[i], num[ind]);
     }
    return ;
}

快排

3、快排最差情况推倒

在快速排序的早期版本中呢,最左面或者是最右面的那个元素被选为枢轴,那最坏的情况就会在下面的情况下发生啦:

1)数组已经是正序排过序的。 (每次最右边的那个元素被选为枢轴)

2)数组已经是倒序排过序的。 (每次最左边的那个元素被选为枢轴)

3)所有的元素都相同(1、2的特殊情况)

因为这些案例在用例中十分常见,所以这个问题可以通过要么选择一个随机的枢轴,或者选择一个分区中间的下标作为枢轴,或者(特别是对于相比更长的分区)选择分区的第一个、中间、最后一个元素的中值作为枢轴。有了这些修改,那快排的最差的情况就不那么容易出现了,但是如果输入的数组最大(或者最小元素)被选为枢轴,那最坏的情况就又来了。(个人觉得还是"三值取中"法最好)

快速排序,在最坏情况退化为冒泡排序,需要比较O(n2)次(n(n - 1)/2次)。

#define swap(a, b) {\
    __typeof(a) __temp = (a);\  
    (a) = (b), (b) = __temp;\
}

//未优化
void quick_sort(int *num, int l, int r) {
    if (l  > r) return ; 
    int x = l, y = r, z = num[l];
    while(x < y) {      
    	while(x < y && num[y] >= z) y--;
      	if (x < y) num[x++] = num[y];  
      	while (x < y && num[x] <= z) x++;
      	if (x < y) num[y--] = num[x];    
    }
    num[x] = z;    
   	quick_sort(num, l, x - 1);
    quick_sort(num, x + 1, r);   
    return ;
}
//优化
inline int middle(int *arr, int l, int r, int mid) {
    int a = arr[l], b = arr[r], c = arr[mid];
    if (a > b) swap(a, b);  
    if (a > c) swap(a, c);
    if (b > c) swap(b, c);  
    return b;
}

void quick_sort(int *num, int l, int r) {
	while (l < r) {      
    	int x = l, y = r, z = (l + r) >> 1;
        int mid = middle(num, x, y, z); 
        do {
            while (x <= y && num[x] < mid) x++;   
            while (x <= y && num[y] > mid) y--;
            if (x <= y) {              
            	swap(num[x], num[y]);
                x++, y--;           
            }
        } while(x <= y);      
        quick_sort(num, x, r);
        r = y;    
    }
    return ;
}

堆排序

#define swap(a, b) {\
    __typeof(a) __temp = (a);\
        (a) = (b), (b) = __temp;\
}
void downUpdata(int *arr, int ind, int n) {
    while ((ind << 1) <= n) {
        int temp = ind, l = ind << 1, r = ind << 1 | 1;        				
        if (l <= n && arr[l] > arr[temp]) temp = l;
        if (r <= n && arr[r] > arr[temp]) temp = r;
        if (temp == ind) break;
        swap(arr[temp], arr[ind]);
        ind = temp;
    }
	return ;
}
void heap_sort(int *arr, int n) {
    arr -= 1;
    for (int i = n >> 1; i >= 1; i--) {
        downUpdata(arr, i, n);
	}
	for (int i = n; i > 1; i--) {
        swap(arr[i], arr[1]);
        downUpdata(arr, 1, i - 1); 
	}
    return ;
}

希尔排序

template<typename T>
void insert_sort(T st, T ed, T delta, T *nums) {
    for (T i = st + delta; i < ed; i += delta) {
        for (T j = i; j > st; j -= delta ) {
            if (nums[j] < nums[j - delta]) {
                swap(nums[j], nums[j - delta]);
            } else {
                break;
            }
        }
    }
}

template<typename T>
void shell_sort(T *nums, T st, T ed) {
    for (int delta = (ed - st) / 2; delta; delta /= 2) {
        for (int i = 0; i < delta ; i++) {
            insert_sort(st + i, ed, delta, nums);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值