常见排序算法(冒泡、插入、选择、递归、快排)

排序算法总结

1. 冒泡排序

思路:

  • 循环遍历数组,比较相邻数字,满足条件就交换。
  • 每次遍历都会把最大或者最小的数冒到最后。

实现:

/* 改进的话,可以加个标志, 当某次遍历没有交换,则说明数组已有序,结束; */
void bubble_sort(int nums[]	, int size)
{
    if (!nums || size <= 1) return ;
    
    /* 升序,size个数,最多遍历size-1次*/
    for (int i=0; i<size-1; ++i)
    {
        for (int j=0; j < size-i-1; ++j)
        {
            if (nums[j] > nums[j+1])
            {
                int tmp = nums[j];
                nums[j] = nums[j+1];
                nums[j+1] = tmp;
            }
        }

    }
    return ;
}

2. 插入排序

思路:

  • 每次从未排序队列选择一个数插入有序队列

实现:

void insert_sort(int nums[], int size)
{
    if (!nums || size <= 1) return;
    
    for (int i=1; i<size; ++i)
    {
        int cur = nums[i];
        int j = i-1; // 有序队列的最后一个元素
        for (; j>=0; --j)
        {
            // 往后移动数据
            if (cur < nums[j])
            {
                nums[j+1] = nums[j];
            }
            else
            {
                break;
            }
        }
        nums[j+1] = cur;
    }
    return;
}

3. 选择排序

思路:

  • 每次从未排序队列选出最小值到已排序队列

实现:

void select_sort(int nums[], int size)
{
    if (!nums || size <= 1) return;
    
    for (int i=0; i<size-1; ++i)
    {
        /* 找出最小数,与nums[i]交换,这个会破坏稳定性 */
        for (int j=i+1; j<size; ++j)
        {
            if (nums[i] > nums[j])
            {
                int tmp = nums[i];
                nums[i] = nums[j];
                nums[j] = tmp;
            }
        }
    }
    return ;
}

4. 归并排序

思路:

  • 递归的把队列二分,再把已排序后的队列合并成一个。
  • 自底向上

实现:

// 归并排序
void merge(int A[], int start, int mid, int end)
{
    int len = end - start + 1;
    int *nums = (int*)malloc(sizeof(int)*len);
    if (!nums) return;
    memset(nums, 0, sizeof(int)*len);
    int p1 = start, p2 = mid+1, i = 0;
    while((p1 <= mid) && (p2 <= end))
    {
        if (A[p1] <= A[p2])
        {
            nums[i++] = A[p1++];
        }
        else
        {
            nums[i++] = A[p2++];
        }
    }
    //尾部处理
    while(p1 <= mid)
    {
        nums[i++] = A[p1++];
    }
    
    while(p2 <= end)
    {
        nums[i++] = A[p2++];
    }
    memcpy(A+start, nums, sizeof(int)*len);
    std::cout << "A[" << start << "..." << end << "]: ";
    for (int j = 0; j<len; ++j)
    {
        std::cout << A[j] << " ";
    }
    std::cout << std::endl;
    
    free(nums);
    
    return;
}

void merge_sort_c(int A[], int start, int end){
    
    if (start >= end)
        return;
    int mid = (start + end)/2;
    merge_sort_c(A, start, mid);
    merge_sort_c(A, mid+1, end);
    merge(A, start, mid, end);
    return;
    
}
void merge_sort(int A[], int length)
{
    if (!A || length <= 0) return;
    
    merge_sort_c(A, 0, length-1);
    
    return;
}

5. 快速排序

思路:

  • 选择队列中适当的数,根据数值大小,把队列分割成两部分。
  • 递归的分割
  • 自顶向下

实现:

//快排
/*
 选择一个数mid分割数组。
 */
int split_opt(int nums[], int start, int end)
{
    // 分割的mid 取数组最后一个值
    int mid = nums[end];
    
    int i = start, j = start;
    
    while (j<=end)
    {
        if (nums[j] <= mid)
        {
            int tmp = nums[i];
            nums[i++] = nums[j];
            nums[j] = tmp;
        }
        ++j;
    }
    
    std::cout << "nums[" << start << "..." << end <<"] " << "mid " << mid <<" : ";
    for (int k=start; k<=end; ++k)
    {
        std::cout << nums[k] << " ";
    }
    std::cout << std::endl;
    
    return i-1;
}

void quick_sort_c(int nums[], int start, int end)
{
    if (start >= end) return;
    int provit = 0;
    provit = split_opt(nums, start, end);
    quick_sort_c(nums, start, provit-1);
    quick_sort_c(nums, provit+1, end);
    return;
}
void quick_sort(int nums[], int length)
{
    quick_sort_c(nums, 0, length-1);
    return;
}

6. 总结

排序算法时间复杂度(最好/平均/最坏)空间复杂度稳定度
冒泡O(n) / O(n*n) / O(n*n)O(1)稳定
插入O(n) / O(n*n) / O(n*n)O(1)稳定
选择O(n*n) / O(n*n) / O(n*n)O(1)不稳定
归并排序始终是 O(nlogn)O(n)稳定
快速排序O(nlogn)/O(nlogn)/O(n*n)O(1)不稳定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值