内部排序1 (插入排序、希尔排序、冒泡排序)

本文详细介绍了内部排序的三种常见算法:插入排序、希尔排序和冒泡排序。插入排序包括直接插入和折半插入,其中折半插入通过减少比较次数提高了效率。希尔排序通过增量序列改进了排序效率。冒泡排序则通过不断交换相邻元素实现排序。这些算法的时间复杂度、稳定性以及适用场景进行了分析,为理解排序算法提供了深入的见解。
摘要由CSDN通过智能技术生成

内部排序(插入排序、希尔排序、冒泡排序)

1.排序的基本概念

(1)排序

将数据元素的无序序列调整为有序序列的过程。

(2)稳定性

假设记录R和S关键字相同,且排序前R在S之前,如果排序后R还在S之前,就称算法是稳定的。

(3)内部排序

在排序的整个过程中,待排序的所有记录全部被放置在内存中处理的排序方法。

(4)八大内部排序

冒泡排序、插入排序、选择排序、希尔排序、快速排序、归并排序、基数排序、堆排序

(5)内部排序的分类

按时间复杂度可分为

a.简单排序方法:时间复杂度位O(n^2)

b.先进排序方法:时间复杂度为O(nlogn)

c.基数排序,其时间复杂度为O(d*n)

按依据原则

a.插入类: 直插排序、二分排序、希尔排序

b.交换类:冒泡排序、快速排序

c.选择类:直接选择排序、树形排序、堆排序

d.归并类:二路归并排序、多路归并排序

e.分配类:多关键字排序、基数排序

(6)排序算法的性能

a.内部排序的基本操作

比较:关键码之间的比较

移动:记录从一个位置移动到另一个位置

b.辅助空间

指除了存放待排序记录占用的存储空间之外,执行算法所需要的其他存储空间。

2.插入排序

(1)基本思想

先将序列中的第1个记录看成一个有序的子序列,然后从第2个记录起逐个插入,直至整个序列变成按关键字非递减有序序列为止。整个排序过程需进行n–1趟排序。

(2)直接插入的过程示例

在这里插入图片描述

r[0]的作用是 监视哨和暂存单元

(3)直接插入的算法

// 对L.r[1..L.length]作直接插入排序
void InsertionSort ( SqList &L ) {
    for (int i=2; i<=L.length; ++i ) { //第2个到第length个记录依次插入
        if (L.r[i].key < L.r[i-1].key){
            L.r[0] = L.r[i]; // 复制为监视哨
            for ( j=i-1; L.r[0].key < L.r[j].key; --j ) //从后往前查找r[i]的正确插入位置
                 L.r[j+1] = L.r[j]; // 大于待插入记录的记录后移
            L.r[j+1] = L.r[0]; // 插入到正确位置
     }
  } 
}

(4)直接插入的算法性能分析

a.空间复杂度:只需要一个记录的辅助空间。O(1)

b.时间复杂度:

假设需要排成升序序列

最好情况下:序列本来是升序的 所以比较次数为n-1,移动次数为0;则时间复杂度为O(n).

最坏情况下:序列本来是降序的 比较次数为(n-2)(n-1)/2,移动次数为(n+4)(n-1)/2,则时间复杂度为O(n^2).

取均值时间复杂度为O(n^2)

c.直接插入算法是稳定的

d.算法简单、容易实现,适用于待排序记录基本有序或待排序记录较小时。

(5)直接插入排序的改进——折半插入排序

a.基本思想

利用折半查找查找“ L.r[1…i-1]中 L.r[i] 的插入位置”的插入排序为折半插入排序。

b.折半插入的算法

void BinsertSort(SqList &L){
    int i,low,high,mid;
    for(i=2; i<= L.length; ++i) {
        L.r[0]=L.r[i]; 
        low=1; high=i-1;//直接修改直接插入排序算法的部分
        while(low<=high) {
            mid=(low+high)/2;
            if (L.r[0].key < L.r[mid].key) high=mid-1; 
            else low=mid+1; 
        }  
        for(int j=i-1; j>=low;--j )  L.r[j+1]=L.r[j]; 
        L.r[low]=L.r[0]; 
    }
}

c.折半插入排序性能分析

折半插入减少了关键字比较次数,移动次数不变,时间复杂度也是O(n^2),但就平均性能而言折半插入优于直接插入

折半插入也是稳定的

3.希尔排序

(1)基本思想

先将整个表分割成若干个子序列,每个子序列由相隔某个“增量”的元素组成, 各个子序列分别进行直接插入排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

(2)希尔排序的过程示例

(3)希尔排序算法

//一趟希尔插入排序。
void ShellInsert (SqList &L, int dk )
{  
   //1.前后记录位置的增量是dk.
   //2.L.r[0]只是暂存单元,不是哨兵。当j<=0时,插入位置已找到
   //先插第1子序列的第2个记录,再插第2子序列的第2个记录…
    for (int i=dk+1; i<=L.length; ++i )   
        if ( L.r[i].key< L.r[i-dk].key) {//将R[i]插入有序增量子表
             L.r[0] = L.r[i]; // 暂存待插入记录在R[0]
             for (j=i-dk; j>0 && (L.r[0].key< L.r[j].key);j -= dk)
                   L.r[j+dk] = L.r[j]; // 记录后移dx个位置,查找插入位置
             L.r[j+dk] = L.r[0]; // 插入 
        }
}//ShellInsert

(4)希尔排序算法分析

研究表明,希尔排序的时间性能在O(n2)和O(nlog2n)之间。有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在n1.23到1.6n1.25之间,即约为O(n1.3 ) 。

4.冒泡排序

(1)冒泡排序的基本思想

两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。小的浮起,大的沉底

(2)冒泡排序的示例

  1. 在这里插入图片描述

(3)冒泡排序的算法

void BubbleSort(SqList &L) 
{ 
      for  (int i = L.length-1; i>0; --i) //i表示趟数,最多n-1趟
    	 {
             for (int j = 0; j < i; ++j) 
                 if (L.R[j] > L.R[j+1]) //逆序
                {    
                      temp=L.R[j]; 
                        L.R[j]=L.R[j+1];//交换
                     L.R[j+1]=temp; 
                 } 
     	 }
} 

(4)冒泡排序的时间性能分析

冒泡排序的时间复杂度为O(n^2),算法是稳定的,适用于数据较少的情况。
mp=L.R[j];
L.R[j]=L.R[j+1];//交换
L.R[j+1]=temp;
}
}
}


**(4)冒泡排序的时间性能分析**

冒泡排序的时间复杂度为O(n^2),算法是稳定的,适用于数据较少的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值