内部排序 ----》插入排序:查找待插入位置 + 移动待插入位置之后的元素 + 插入数据

    》》 插入排序是一种简单直观的排序方法,其基本思想在于每次将一个待排序的记录,按其关键字

           大小插入到前面已经排好序的子序列中,直到全部记录插入完成。

1、直接插入排序

    》》 直接插入排序进行的两项工作:

             1)、从前面有序的子表中查找出待插入元素应该被插入的位置

             2)、给插入位置腾出空间,将待插入元素复制到表中的插入位置

             注意:这种排序方法是边比较边移动元素。

             补充:这种方法在排序的过程中,向有序表中逐个地插入元素的操作进行了 n -1 趟 ,

                           每趟操作都分为“比较关键字”和“移动元素”

     》》 直接插入排序图解

              

              说明1:直接插入排序法是从“无序段”的 第 i 位置开始取数,将取到的数放入 [ 0 ...i-1] 段中合适的位置,使得

                        [ 0 ... i ] 段中的数据依次是有序的。

       》》 直接插入排序的代码示例:

             

// 注释:下面的案例中使用 A[0] 作为“哨兵”,其实是为了复制被取出的元素,这样
//       将前面的元素后移的时候,不会因为元素被覆盖导致数据的丢失
void InsertSort(ElemType  A[]  , int n){

   int i , j ;
    
    // 说明1:第0个位置不放任何数据,A[0] 将要作为“哨兵”
    // 说明2:从第 2 个位置开始取数据,直到取到最后一位
   for(i = 2 ; i <= n ; i++){
             // 如果当前取到的元素比它的前驱元素值小,执行if内部的操作
            if( A[i].key < A[i-1].key ){
                  // 将 A[0] 位置的值作为“哨兵”
                 A[0] = A[i];
                  
                  // j 记录的是依次被比较的数据的下标
                  for(j = i -1 ; A[0].key < A[j].key ; --j ){
                       // 如果哨兵的值比当前 j 坐标下的值小,那么当前 j 位置的值
                       // 需要向后移动一位,空出当前 j 位置的空间,同时 j 指针向前
                       //  移动一位
                       A[j+1] = A[j];    
                  }
                 
                  // 当哨兵的值不小于第 j 位置的值,上面的 for 循环将退出,
                  // 此时,j 指针后一位的位置是空着的,那么就把“哨兵的值”复制到
                  // j + 1 位置
                  A[j+1] = A[0] 
            }
               
    }
}

2、折半插入排序【对直接插入排序算法的改进】

     》》 基本思想:将比较和移动操作分离出来,即先折半查找出元素的待插入位置,然后再统一地移动待插入

             位置之后的所有元素

     》》 折半插入排序的代码示例:

             

void InsertSort(ElemType A[] , int n){

     // i  表示被取出的元素的位置
     // j  表示移动元素的开始位置
     // low , high , mid 三个指针都是为了使用折半查找而设置的三个值
    int i , j , low , high ,  mid ;

     //  A[0] 位置上不存放任何数据,用来作“哨兵”
     //  从第 2 个位置开始取数
    for( i = 2 ; i <= n ; i++ ){
            // 将 A[i] 中的元素暂时存入 A[0] 中
            A[0] = A[i];

            // 下面的代码是为了查找合适的插入位置,使用折半查找法
             low = 1  , high = i -1 ;
            while( low < high ){
                // 取中间点
                mid = (low+high)/2;
                // 将 A[0] 中的值与 中间点的值,进行比较
                // 如果中间点的值大于即将插入的值,那么插入的位置一定在左半子表,
                // 将范围缩小到左半子表
                if( A[mid].key > A[0].key ){
                      high = mid -1 ;
                }else{
                  // 如果中间点的值不大于即将插入的值,那么插入的位置一定在右半子表,
                  //  将范围缩小到右半子表
                   low = mid + 1 ;     
                }
            }

            // 上面的 while 循环退出的时候,low == high 
            // 即,被插入的位置就是 high 指针所指向的位置
            // 将 high 位置之后的所有元素后移一位【包括high 位置的元素也后移一位】,
            // 空出 high 位置的空间
             for( j = i -1 ; j >= high ; --j){
                 A[j+1] = A[j];
             }

             // 将 A[0] 中的元素插入到 high 的位置
             A[high] = A[0];
            
    }

}

3、希尔排序【分段多次使用直接插入排序】

    》》希尔排序的基本思想:先将待排序表分割成若干个形如 L[ i, i+ d , i + 2d , ...., i + kd ] 的“特殊”子表,分别

          进行直接插入排序,当整个表中元素已经呈现“基本有序”时,再对全体记录进行一次直接排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小达人Fighting

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值