《大话数据结构》第九章 排序

第九章深入探讨了各种排序算法,包括冒泡排序及其优化、简单选择排序、直接插入排序、希尔排序、堆排序、归并排序以及快速排序。每种算法都讲解了基本思想、实现方式和时间复杂度,重点讨论了如何优化算法性能。例如,冒泡排序通过设置标记避免多余步骤,快速排序则通过选取枢轴和优化交换来提升效率。
摘要由CSDN通过智能技术生成


第九章 排序

排序的基本概念和分类

排序的稳定性
k i = k j k_i=k_j ki=kj时,如果排序前 r i , r j r_i,r_j ri,rj的前后关系和排序后不变,则称此排序方法是稳定的。

内排序和外排序:内排序是排序过程中,待排序的记录全部放置在内存中;外排序是由于排序的记录个数太多,不能同时放置在内存,排序过程中需要在内外存之间多次交换数据才能进行。

影响排序算法的性能的三个方面

  1. 时间性能
  2. 辅助空间
  3. 算法的复杂度

根据排序中主要操作方法分类

  • 插入排序
  • 交换排序
  • 选择排序
  • 归并排序

排序用到的结构和函数
顺序表结构:

#define MAXSIZE 10
typedef struct SqList
{
   
    int r[MAXSIZE+1];    // 存储要排序数组,r[0]用作哨兵或临时变量
    int length;    // 用来记录顺序表的长度
}

数组两元素交换:

void swap(SqList *L, int i, int j)
{
   
    int temp = L->r[i];
    L->r[i] = L->r[j];
    L->r[j] = temp;
}

冒泡排序

思路:冒泡排序是一种交换排序,基本思想是两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

最简单的冒泡实现

void BubbleSort0(SqList *L)
{
   
    int i, j;
    for (i=1; i<L->length;i++)
    {
   
        for (j=i+1; j<=L->length; j++)
        {
   
            if (L->r[i] > L->r[j])
            {
   
                swap(L, i, j);    // 换i和j还是挺笨的
            }
        }
    }
}

正常冒泡算法

void BubbleSort(SqList *L)
{
   
    int i, j;
    for (i=1; i<L->length;i++)
    {
   
        // j从后往前循环,小的往前送
        for (j=L->length-1; j>=i; j--)
        {
   
            if (L->r[j] > L->r[j+1])
            {
   
                swap(L, j, j+1);
            }
        }
    }
}

冒泡排序优化

普通冒泡法存在的问题:比如{2,1,3,4,5,6,7,8,9},只需要交换第一个位置和第二个位置,如果使用上面的冒泡,或有很多多余的步骤。

解决的思路:如果已经序列已经有序,不再发生交换,那么可以做个标记,停止循环。

实现代码

void BubbleSort2(SqList *L)
{
   
    int i, j;
    Status flag = True;
    //若flag为false则表示不再发生交换,因此退出循环
    for (i=1; i<L->length && flag; i++)
    {
   
        flag = FALSE;
        for (j=L->length-1; j>=1; j--)
        {
   
            if (L->r[j] > L->r[j+1])
            {
   
                swap(L, j, j+1);
                flag = True;       // 如果有数据交换,则flag为true
            }
        }
    }
}

冒泡排序的时间复杂度
最好的情况:只需要n-1次比较,此时复杂度为 O [ n ] O[n] O[n]
最坏的情况:待排序的数组为逆序,需要比较 ∑ i = 2 n ( i − 1 ) = n ( n − 1 ) 2 \sum^n_{i=2}(i-1)=\frac{n(n-1)}{2} i=2n(i1)=2n(n1)次,时间复杂度为 O [ n 2 ] O[n^2] O[n2]


JAVA实现冒泡排序

工具类

public class utils {
   
    public static void swap(int[] L, int i, int j){
   
        int temp = L[i];
        L[i] = L[j];
        L[j] = temp;
    }

    public static void show(int[] a) {
   
        for (int i = 0; i < a.length; i++) {
   
            System.out.println(a[i]);
        }
    }
}

方法类

import Sort.utils.utils;

public class bubbleSort {
   
    public static void main(String[] args) {
   
        int[] a = {
   62, 58, 88, 47, 73, 99, 35, 52, 93, 37};
        BubbleSort0(a);
        // utils.show(a);

        int[] b = {
   62, 58, 88, 47, 73, 99, 35, 52, 93, 37};
        BubbleSort1(b);
        utils.show(b);
    }

    // 当不再发生交换时,停止循环
    private static void BubbleSort1(int[] a) {
   
        int len = a.length;
        boolean flag = true;
        for (int i=len-1; i>=0 && flag; i--){
   
            flag = false;
            for (int j=0; j<i; j++){
   
                // 发生交换再改变 比 不改变再标记 更简单
                if (a[j] > a[j+1]){
   
                    utils.swap(a, j, j+1);
                    flag = true;
                }
            }
        }
    }

    // 升序
    private static void BubbleSort0(int[] a) {
   
        int len = a.length;
        for (int i = len-1; i >=0; i--) {
   
            for (int j=0; j < i; j++){
   
                if (a[j] > a[j+1]){
   
                    utils.swap(a, j, j+1);
                }
            }
        }
    }
}

简单选择排序

思路:通过 n − i n-i ni次关键字间的比较,从 n − i + 1 n- i + 1 ni+1个记录中选出关键字最小的记录,并和第 i i i个记录交换之。

代码实现

void SelectSort(SqList *L)
{
   
    int i, j, min;
    for (i=1; i<L->length; i++)
    {
   
        min = i;
        for (j=i+1; j<=L->length; j++)
        {
   
            // 记录最小的,以待交换
            if (L->r[min] > L->r[j])
                min = j;
        }
        if (i!=min)    // 如果不等,说明找到了最小值
            swap(L, i, min);

时间复杂度
无论好坏,比较次数都是 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1),交换次数最好为0,最差为 n − 1 n-1 n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值