内部排序笔记

目录

一、排序的基本概念

二、插入排序

2.1 直接插入排序

代码实现

效率分析

2.2 折半(二分)插入排序

算法思想

代码实现

 效率分析

2.3 希尔排序

效率分析

三、交换排序

基本思想

冒泡排序

快速排序

四、直接选择排序

算法思想

 代码实现

五、总结


一、排序的基本概念

排序:将一组杂乱无章的数据按一定规律次序排列起来。及:将无序序列排成一个有序数列(由小到大或由大到小)的运算。

 基于顺序表的存储结构来排序:

#define MAXSIZE 20
typedef int KeyType;

typedef struct{
    KeyType key;//关键字
    InfoType otherinfo;
}RedType;

typedef struct{
    RedType r[MAXSIZE + 1];//r[0]一般作哨兵或缓冲区
    int length;
}SqList;

二、插入排序

在有序序列中插入一个元素,保持序列有序,有长度不断增加。

2.1 直接插入排序

用顺序查找法查找插入位置。

代码实现

void InsertSort(SqList &sl){
    int i,j;
    for(int i = 2;i<=sl.length;i++){
        if(sl.r[i].key < sl.r[i-1].key){//比较关键字的大小
            sl.r[0] = sl.r[i];//将目标元素存储在哨兵中
            j = i - 1;
            for(j = i-1;sl.r[0].key<sl.r[j].key;j--)//比较关键字的大小
                sl.r[j+1] = sl.r[j];//将关键字大的元素向后移
            sl.r[j] = sl.r[0];//将目标插入
        }
    }
}//顺序插入

效率分析

原始数据越接近有序,排序速度越快。

最坏情况:原始数据是逆序的。T(n) = O(n^2)

平均情况下,耗时差不多是最坏情况的一般。T(n) = O(n^2)

要提高查找速度:减少元素的比较次数,减少元素的移动次数。

空间复杂度:只需要一个哨兵空间。O(1)


2.2 折半(二分)插入排序

算法思想

对于即将要进行排序的元素i,将列表中已经排序好的第1个元素设为low,最后一个元素,即第i-1个元素设为high。将i的关键字与二者的中间元素mid的关键字相比:若i<mid,则high= mid-1,再次进行比较;若i>=mid,则low = mid + 1,再次进行比较。直到high<low,high在low的左边,则此时high+1的位置就是要插入的位置。

在过程中,i的关键字至于每次mid的关键字进行比较,并不是在一次折半后,和mid的左边/右边的全部元素的关键字进行比较;需要一直进行折半,直到不能继续折。

代码实现

void BInsertSort(SqList &sl){
    //int i,j;
    //int low,high,mid;
    for(int i = 2;i<=sl.length;i++){
        sl.r[0] = sl.r[i];//目标元素存入哨兵位置
        int low = 1;
        int high = i-1;
        while(low<=high){
            int mid = (low + high)/2;
            if(sl.r[0].key<sl.r[mid].key)
                high = mid - 1;
            else
                low = mid + 1;
        }//循环结束时,high在low左边,high+1就是插入位置
        for(int j = i-1;j>=high + 1;j--)
            sl.r[j+1] = sl.r[j];
        sl.r[high + 1] = sl.r[0];
    }
}//折半插入

 效率分析

1.折半查找比顺序查找快,所以折半插入排序比直接插入排序快。

2.其所需比较次数与序列的初始排列无关,仅与其对象个数相关。

3.当n较大时,其关键码比较次数比直接插入排序的最坏情况好得多,但比其最好情况差;

   当队列在初始已经接近有序,直接插入排序比折半插入排序执行的关键码比较次数要少。

4.折半插入排序的对象移动次数与直接插入排序相同,依赖于队列的初始排列。

5.时间复杂度:O(n^2);空间复杂度:O(1)。


2.3 希尔排序

算法思想

先将整个待排序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

 代码实现

void ShellInsert(SqList &sl,int dk){
    for(int num=1;num<=dk;num++){
        int i,j;
        for(i = 1+dk;i<=sl.length;i = i+dk){
            if(sl.r[i].key<sl.r[i-dk].key){
                sl.r[0] = sl.r[i];//存放目标元素
                for(j = i-dk;sl.r[0].key<sl.r[j].key;j = j-dk){
                    sl.r[j+dk] = sl.r[j];}//将元素后移
                sl.r[j] = sl.r[0];//插入目标元素
            }
        }
    }
}//希尔插入
void ShellSort(SqList &L,int dlta[],int t){//dlta[]为存放步长的数组,t为需要进行希尔插入的次数。
    for(int k = 0;k<t;k++)
        ShellInsert(L,dlta[k]);//进行一趟步长为dlta[k]的希尔插入
}//希尔排序主程序

效率分析

1.其算法效率与增量序列的取值有关。

 2.希尔排序是一种不稳定的排序算法。

 3.时间复杂度为n和步长d的函数

 空间复杂度为O(1).

4.增量序列的最后一个增量值必须为1.

5.不宜在链式存储结构上实现。


三、交换排序

基本思想

两两比较,如果发生逆序则交换,直到所有记录都排好序为止。

冒泡排序

基本思想:每趟不断将记录两两比较,并按“前小后大”的规则交换。

若按升序排列,冒泡排序的第i次过程就是一遍遍的将前n+1-i个元素中最大的元素排到最后。

若有n个元素,则需排列n-1趟;第 i 趟,需要比较n - i次。

void bubble_sort(SqList &sl){
    int m,j;
    RedType x;//用于临时存储
    for(m = 1;m<=sl.length - 1;m++){//总共需m趟
        for(j = 1;j<=sl.length - m;j++)
            if(sl.r[j].key>sl.r[j+1].key){//发生了逆序
                x = sl.r[j];
                sl.r[j] = sl.r[j+1];
                sl.r[j+1] = x;//交换
            }

    }
}//冒泡排序

若在某一趟中,没有发生交换,则说明元素已经排列好,后面的就不需要继续了。因此可以改进:

void bubble_sort(SqList &sl){
    int m,j;
    RedType x;//用于临时存储
    int flag = 1;
    for(m = 1;m<=sl.length - 1&&flag == 1;m++){//总共需m趟
        flag = 0;
        for(j = 1;j<=sl.length - m;j++)
            if(sl.r[j].key>sl.r[j+1].key){//发生了逆序
                x = sl.r[j];
                sl.r[j] = sl.r[j+1];
                sl.r[j+1] = x;//交换
                flag = 1;//如果发生了交换,就将flag置为1,则下次循环可以进行;
                         //否则就会停止循环,后面的就不会继续了。
            }

    }
}//冒泡排序

效率分析

优点:每趟结束时,不仅能挤出一个最大值到最后,还能同时理顺其他元素。

最好情况(正序):

        比较次数:n-1

        移动次数:0

最坏情况(逆序):

时间复杂度:最好是O(n);最坏是O(n^2);平均是O(n^2)

快速排序

算法思想

1.任取一个元素为中心,将所有比它小的放在它左边,比它大的放它右边,形成两个子表。

2.对各子表重新选择中心元素并依此规则调整,直到每个子表的元素只剩一个。

代码实现

int Partition(SqList &sl,int low,int high){
    sl.r[0] = sl.r[low];
    int pivotkey = sl.r[low].key;
    while(low<high){
        while(low<high&&sl.r[high]>=pivotkey)
            high--;//将比中心点大的数保留在后面不动
        sl.r[low] = sl.r[high];//将比中心点小的移到前面
        while(low<high&&sl.r[low]<=pivotkey)
            low++;//将比中心点小的留在前面不动
        sl.r[high] = sl.r[low];//将比中心点大的移到后面
    }
    sl.r[low] = sl.r[0];
    return low;
}

void Quick_Sort(SqList &sl, int low,int high){
    if(low<high){
        int pivoloc;
        pivoloc = Partition(sl,low,high);
        Quick_Sort(sl,low,pivoloc - 1);
        Quick_Sort(sl,pivoloc + 1,high);
    }

}

效率分析

时间复杂度:

空间复杂度:

不是原地排序,使用了递归,调用了系统的栈,而栈的长度取决于递归调用的深度。

稳定性:快速排序不是一种稳定的排序方法。

 快速排序不适合对原本有序或基本有序的序列进行排列。会退化为冒泡排序。

 划分元素的选取是影响时间性能的关键。


四、直接选择排序

算法思想

在待排序的数据中选出最大(小)的元素放在最终位置。

 代码实现

void SelectSort(SqList &sl){
    for(int i = 1;i<sl.length;i++){
        int k = i;
        for(int j = i+1;j<=sl.length;j++)
            if(sl.r[j].key<sl.r[k].key)
                k = j;//记录最小值位置,k就是min
        if(k!=i){   //存在比sl.r[i]小的
            RedType x;
            x = sl.r[i];
            sl.r[i] = sl.r[k];
            sl.r[k] = x;    //交换
        }
    }
}//直接交换排序

效率分析

移动次数:最好:0;最坏:3(n-1)

比较次数:

时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:直接选择排序是不稳定排序。


五、总结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值