排序问题

本文详细探讨了C语言中的三种排序算法:简单选择排序、冒泡排序和快速排序。对于每种排序,都进行了逻辑分析和流程处理的阐述,并讨论了它们的时间复杂度。特别指出,冒泡排序在数据接近有序时性能最佳,而快速排序在数据随机分布时效率最高。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C语言里的排序问题:

1、简单选择排序

1.1、逻辑分析

简单选择排序: 就是从0开始,每次确定一个位置的元素。
假设当前需要确定的位置下标为i,则将i处的元素与后面的元素逐个比较,记录最小元素的下标,最后将记录下标的元素与i元素进行交换。(本质为一种选择排序)

代码为:

void SimpleSort(int *arr, int len)
{
    for (int i = 0; i < len-1; i++) {
        int temp = 0;
        int index = i;  //保存最小值的下标
        for (int j = i + 1; j < len; j++) {
            if (arr[index] > arr[j]) {
                index = j;
            }
        }
        temp = arr[i];
        arr[i] = arr[index];
        arr[index] = temp;
    }
}


2、冒泡排序

2.1、逻辑分析

冒泡排序:顾名思义就是两两比较交换慢慢的最数列的最小值浮到数列的最顶端

2.2、流程处理

假设要对一个大小为 N 的无序序列进行升序排序(即从小到大)。 

(1) 每趟排序过程中需要通过比较找到第 i 个小的元素。

所以,我们需要一个外部循环,从数组首端(下标 0) 开始,一直扫描到倒数第二个元素(即下标 N - 2) ,剩下最后一个元素,必然为最大。

(2) 假设是第 i 趟排序,可知,前 i-1 个元素已经有序。现在要找第 i 个元素,只需从数组末端开始,扫描到第 i 个元素,将它们两两比较即可。

所以,需要一个内部循环,从数组末端开始(下标 N - 1),扫描到 (下标 i + 1)。

1、假设数列为: 5,8,1,3,4, 7(红字为发生变化的元素)
第一次交换:5, 18,3,4,7
第二次交换: 15,8,3,4,7    //找出第一个元素
第三次交换:1,5, 38,4,7
第四次交换:1, 35,8,4,7 //找出第二个元素
第五次交换:1,3,5, 48,7
第六次交换:1,3, 45,8,7 //找出第三个元素
第七次交换:1,3,4,5, 78

1.3、时间复杂度

冒泡法的比较次数与数列的初始排序无关。 如果有 n个元素,则总比较次数为n(n-1)/2。然而交换次数是和数列的初始排序是有关的

当数列正序时,交换次数最少为0,当数列反序时,交换次数最多为n(n-1)/2

所以当数据越接近正序时,冒泡排序性能越好。

代码为:
void BubbleSort(int *arr, int len)
{
    int temp = 0;
    for (int i = 0; i < len-1; i++) {
        for (int j = len - 1; j > i; j--) {
            if (arr[i] > arr[j]) {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

3、快速排序

3.1、逻辑分析

1、先选择一个数为基准数;
2、将比这个数小的数都放到它的左边,比它大的都放到右边,从而找到这个数在整个数列中的位置;
3、以这个数为分隔,将整个数列分成两部分,运用递归的思想将这两部分重复第二步骤;
如下图:


3.2、流程处理

1、假设数列为:2,4,5,1,3(红字为low和high分别指向的数字)
假设这个基准数位2,先用一个变量val记录这个数字
用变量low和high分别指向最低位(2)和最高位(3)
2、将val与high指向的数字进行比较,val>high时将high指向的数字赋给low指向的数字,否则high指向的位置左移
此时数列为:1,4,5,1,3
3、将val与low指向的数字进行比较,val<low时将low指向的数字赋给high指向的数字,否则low指向的位置右移
此时数列为:1,4,5,4,3
重复2的步骤此时low指向的位置与high指向的位置重合,这个位置就是基准数val(2)在数列中的位置
此时数列为:1,2,5,4,3
代码为:
int FindPivotIndex(int *a, int low, int high)
{
    int val = a[low];
    while (low < high) {
        while (low < high && val <= a[high]) {
            high--;
        }
        a[low] = a[high];
        while (low < high && val >= a[low]) {
            low++;
        }
        a[high] = a[low];
    }
    a[low] = val;
    
    return high;
}

以这个数为分隔,将整个数列分成两个数列,运用递归的思想,重复上述代码
代码为:
void QuickSort(int *a, int low, int high)
{
    int pivotindex = 0;
    pivotindex = FindPivotIndex(a, low, high);
    if(low < high)
    {
        QuickSort(a, low, pivotindex-1);
        QuickSort(a, pivotindex+1, high);
    }
}

3.3、时间复杂度

当数据有序时,以第一个关键字为基准分为两个子序列,前一个子序列为空,此时执行效率最差。

而当数据随机分布时,以第一个关键字为基准分为两个子序列,两个子序列的元素个数接近相等,此时执行效率最好。

所以,数据越随机分布时,快速排序性能越好;数据越接近有序,快速排序性能越差。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值