几种常见排序算法总结(个人理解与代码实现)

一、冒泡排序

从排列的第一个元素开始,比较与其右元素的大小关系,不符合排序要求则交换,如:从左到右正向排序,左大于右,则交换,但是排序比较的焦点始终加一地前进。这样一轮比较下来,最大的一定排到了最后(从第一个开始与后面的比较,遇到小的直接交换位置,遇到更大的则选择更大的,带着更大的往后比较),这样有多少数,就排序多少数-1轮,最后全部排序完


冒泡排序算法原理示例图
请添加图片描述


代码实例:

#include <stdio.h>

void bubblesort(int *a, int n)
{
    for (int i = 0; i < n - 1; i++) //一共n个数,最坏情况进行n-1轮排序
    {
        int changed = 0,temp = 0; //记录一轮排序交换的次数,temp用于交换

        for (int j = 0; j < n-1; j++)
        {
            if(a[j]>a[j+1])//前面比后面大,就交换
            {
                temp = a[j];
                a[j] = a[j+1];
                a[j+1] = temp;
                changed += 1;//交换次数+1
            }
        }
        if(changed == 0)//如果有一轮没有发生交换,说明排序好了,提前结束
            break;
    }
}

int main()
{
    int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    bubblesort(a, 10);
    for (int i = 0; i < 10; i++)
        printf("%d ", a[i]);

    printf("\n");
    return 0;
}

输出:

0 1 2 3 4 5 6 7 8 9 
  • 比较的循环最多进行n-1次,最坏的情况就是上面举例的这样,逆序的用冒泡排正序,这样时间复杂度就直接到最大 : O( n2),最好的情况当然就是已经排序好的,一遍排序就结束: O(n)。
  • 在循环当中加入一个交换次数的比较,交换次数为0就表示排序完成,就停止整个循环,这样就提高了排序的效率

冒泡排序的比较次数
每一轮的元素都要和其他未排序好的元素进行比较
第一轮的比较次数是n-1(n为个数),第二轮就不用再比较最后的最大数,依次为n-1,n-2,…1,共n(n-1)/2次
时间复杂度: O(n2) 空间复杂度 :O(1)

二,选择排序

排序原理:

  • 在排序序列中找到最大(小)的数,与a[0]交换位置
  • 在剩余序列中找到最大(小)的数,与a[1]交换位置
  • …………
  • 在剩余两数中找到最大(小)的数,与a[n-1]交换位置

选择排序算法原理示例图:
在这里插入图片描述


代码实例:

#include <stdio.h>

void select_sort(int *a, int n)
{
    for (int i = 0; i < n; i++)//从0开始,一共进行n-1轮比较
    {
        int target = i; //用于记录已知排序好的元素的位置

        for (int j = i + 1; j < n; j++)//从已知排序好的下一位出发
        {
            if (a[j] < a[target]) //找到未排序序列中的最小数
            {
                int temp = a[target];
                a[target] = a[j];
                a[j] = temp;
            }
        }
    }
}

int main()
{
    int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    select_sort(a, 10);
    for (int i = 0; i < 10; i++)
        printf("%d ", a[i]);

    printf("\n");
    return 0;
}

输出:

0 1 2 3 4 5 6 7 8 9 

选择排序将排序序列分为了已排序好的部分与未排序好的部分,逐渐将未排序好部分中的数提出到排序好的部分。

由此:就可以有另一种双向选择排序的方式,一趟排序进行最大最小两个选择

代码实例:

#include <stdio.h>

void select_sort2(int *a, int n)
{
    for (int i = 0, j = n - 1; i < j; i++, j--)
    //i是一趟排序里面的第一个,j是一趟排序里面的最后一个
    {
        int min, max = i;//一开始就取一个作比较,不是这个也可以

        for (int k = i; k <= j; k++)//找到剩余序列中的最大与最小下标
        {
            if (a[k] < a[min])//有更小就存一下下标
                min = k;

            if (a[k] > a[max])//有更大就存一下下标
                max = k;
        }

        int temp = a[i];//交换最小
        a[i] = a[min];
        a[min] = temp;

        if(i == max)//如果最大值刚好在最左,那么为了不重复交换
        {
            max = min;//刚才最小的位置就应该是真正最大的位置
        }

        int temp2 = a[j];//交换最大
        a[j] = a[max];
        a[max] = temp2;
    }
}

int main()
{
    int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    select_sort2(a, 10);
    for (int i = 0; i < 10; i++)
        printf("%d ", a[i]);

    printf("\n");
    return 0;
}

输出:

0 1 2 3 4 5 6 7 8 9 

选择排序
时间复杂度: O(n2) 空间复杂度 :O(1)

三,插入排序

排序原理:

  • 将排序序列分为了已排序好的部分与未排序好的部分,逐渐将未排序好部分中的数提出到排序好的部分
  • 把序列中第一个元素作为排序好的第一个元素
  • 把第二个元素插入到排序的区域中合适的位置
  • 对后面的元素重复上一步骤

插入排序算法原理示例图
在这里插入图片描述


代码实例:

#include <stdio.h>

void insertSort(int *a, int n)
{
    for (int i = 1; i < n; i++)
    //因为把第一个当做已经排序好的,所以一共进行n-1轮
    {
        int temp = a[i];//未排序的第一个赋值给temp
        int j = 0;//定义j=0
        for (j = i - 1; j >= 0; j--)//开始循环比较
        {
            if (temp < a[j])
            {
                a[j + 1] = a[j];//第一轮:9换到了8的位置上,变成9976543210
            }
            else
            {
                break;
            }
        }
        // printf("%d\n", j);
        a[j + 1] = temp;//这时j=?
        //第一轮:把提前存储的8换到了9上,变成,8976543210

        for (int p = 0; p < 10; p++)//这里把每一轮的排序结果都输出一次
            printf("%d ", a[p]);//看得到排序的过程

        printf("\n");
    }
}

int main()
{
    int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    insertSort(a, 10);
    // for (int i = 0; i < 10; i++)
    //     printf("%d ", a[i]);

    printf("\n");
    return 0;
}

输出:

8 9 7 6 5 4 3 2 1 0 
7 8 9 6 5 4 3 2 1 0
6 7 8 9 5 4 3 2 1 0
5 6 7 8 9 4 3 2 1 0
4 5 6 7 8 9 3 2 1 0
3 4 5 6 7 8 9 2 1 0
2 3 4 5 6 7 8 9 1 0
1 2 3 4 5 6 7 8 9 0
0 1 2 3 4 5 6 7 8 9

插入排序
时间复杂度: O(n2) 空间复杂度 :O(1)

四,希尔排序

排序原理:

  • 先将待排记录序列分割成为若干子序列分别进行插入排序,
  • 待整个序列中的记录"基本有序"时,再对全体记录进行一次直接插入排序。
  • 对一个“几乎”已经排好序的无序序列,插入排序的效率是很高的,可以达到线性排序的效率。比如,当序列中只有一位元素没有在适当的位置,那么整个序列只需要移动该序列的位置即可达到完成排序的任务。希尔排序就是利用这一点,进行了一个插入排序的升级

在这里插入图片描述

代码实例:

#include <stdio.h>

void shellSort(int *a, int n)
{
    int length = n;//获取数组长度
    int i, j, k;//定义变量
    do//do-while循环(先做再判断)
    {
        length = length / 3 + 1;//保证至少有一轮
        for (i = 0; i < length; i++)
        //循环比较的组的次数,例如十个数,有四组比较,循环四组
        {
            for (j = i + length; j < n; j += length)
            //同一组的进行比较排序
            {
                if (a[j] < a[j - length])
                {
                    int temp = a[j];
                    for (k = j - length; k >= 0 && temp < a[k]; k -= length)//插入排序
                    {
                        a[k + length] = a[k];
                    }
                    a[k + length] = temp;
                }
            }
        }
    } while (length > 1);
}

int main()
{
    int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    shellSort(a, 10);
    for (int i = 0; i < 10; i++)
        printf("%d ", a[i]);

    printf("\n");
    return 0;
}

运行结果:

0 1 2 3 4 5 6 7 8 9 

希尔排序
时间复杂度: O(n2) 空间复杂度 :O(1)
希尔排序的效率依赖于递减增量序列的选择,时间复杂度最坏的情况是O(nlog2n)。

五、快速排序

排序原理:

  • 通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。
  • 一趟快速排序的具体过程可描述为:从待排序列中任意选取一个记录(通常选取第一个记录)作为基准值,然后将记录中关键字比它小的记录都安置在它的位置之前,将记录中关键字比它大的记录都安置在它的位置之后。这样,以该基准值为分界线,将待排序列分成的两个子序列。

代码实例:

#include <stdio.h>

void quickSort(int *a, int start, int end)
{
    int i = start;
    int j = end;

    int baseval = a[start];
    //(通常选取第一个记录)作为基准值
    while (i < j)
    {
        while (i < j && a[j] >= baseval) // 从右向左找第一个小于x的数
        {
            j--;
        }
        if (i < j)
        {
            a[i++] = a[j];
        }

        while (i < j && a[i] < baseval) // 从左向右找第一个大于等于x的数
        {
            i++;
        }
        if (i < j)
        {
            a[j--] = a[i];
        }
        a[i] = baseval;

        quickSort(a, start, i - 1);//递归
        quickSort(a, i + 1, end);
    }
}

int main()
{
    int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    quickSort(a, 0, 9);

    for (int i = 0; i < 10; i++)
        printf("%d ", a[i]);

    printf("\n");
    return 0;
}

运行结果:

0 1 2 3 4 5 6 7 8 9
几种常见排序 基于比较的排序算法: 下界是 nlgn 1.1 SelectionSort:每次选出最下的元素,放在当前循环最左边的位置。 1.2 BubbleSort:每次比较相邻的两个数,使得最大的数像气泡一样冒到最右边。 1. 3 InsertionSort:每次拿起一个数,插入到它左边数组的正确位置。 1.4 QuickSort:选择一个数,作为标准,小于它的放在左边,大于它的放在右边。并把它放在中间;递归地对左右子数组进行排序。 实现时:1. 确定递归结束条件,初始化左右游标, 选择标准数; 2. while循环,do while实现两个游标同时向中间移动,置换; 3. 置换标准数和右边游标所指的数; 4. 递归调用,对左右子数组进行排序。 1. 5 HeapSort:用最大堆实现实现时:建堆:置换堆顶元素和最后一个元素,堆大小减少,保持新的堆为最大堆; 保持最大堆: 从底向上依次保持最大堆,从第一个父节点到根部。 1.6 MergeSort:拆分数组,递归实现排序,二路归并。用哨兵来阻止游标的越界。 线性时间运行的算法: 1.7 CountingSort: 假设数据分布在0到k之间的。对于每个输入x,确定出小于x的数的个数。假设小于x的数有17个,那么x就应该在第18个输出位置。 1. 8 Radix sort(基数排序):从最低位开始,每位采用稳定的排序算法(如计数排序)。 1.9 Bucket sort:当输入数据比较均匀时采用。 先将数据区间分为n个桶,把数据分放到对应的桶中;对桶内的数据采用插入排序;再把各个桶的排序结果串起来。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值