八大排序之选择类排序

直接插入排序

  • 在有序数组中插入一个元素,可以作为一种排序方法的基础
  • 只有一个元素的数组是一个有序数组,对n个元素的数组,可以从第一个元素所构成的单元数组开始,不断实施插入操作
  • 插入第二个元素,得到2个元素的有序数组。插入第三个元素,得到3个元素的有序数组
  • 如此反复,得到n个元素的有序数组

示例

对序列:6,5,8,4,3,1 进行直接插入排序

  • 图中灰色部分代表待排序列
  • 图中透明部分代表已排序列
int main()
{
    int a[10] = { 6,5,8,4,3,7 };

    int temp, j;
    for (int i = 1; i < 6; ++i){
        temp = a[i];
        for (j = i - 1; j >= 0 && temp < a[j]; --j){
            a[j + 1] = a[j];
        }
        a[j + 1] = temp;
    }
    j = 0;
    while (j < 6){
        printf("%d", a[j]);
        ++j;
    }
    return 0;
}

时间复杂度分析

由直接插入排序代码,选取最内层

a[j + 1] = a[j];

作为基本操作语句

  1. 考虑最坏的情况,即整个序列是逆序的,O(n^2)
  2. 考虑最好的情况,即整个序列是有序的,O(n)

综上所述,本算法的平均时间复杂度O(n^2)

空间复杂度分析

  • 算法所需的辅助存储空间不随待排序列规模的变化而变化,是个常量,O(1)

折半插入排序

  • 与直接插入排序思想类似,区别是查找插入位置的方法不同,折半插入排序是采用折半查找法查找插入位置的
  • 将待排序的记录R[i],通过折半查找的方式在有序序列中查找插入位置

示例

对序列:13,38,49,65,76,97,27,49进行一趟折半插入排序。

前6个元素已经排好序列,查找27的插入位置

  1. mid = (0 + 5)/2 = 2,当前位置,27 < 49,27的插入位置在49的低半区
  2. h = mid - 1,mid = (0 + 1)/2 = 0,当前位置,27 > 13,27插入位置在13的高半区
  3. low = mid + 1,mid = (1 + 1)/2 = 1,27 < 38,27的插入位置在38低半区
  4. high = m - 1 = 0,high < low,折半查找结束,27的插入位置在high之后,插入位置后面的元素后移

int main()
{
    // a[0]为存储临时变量的位置
    int a[9] = { 0, 13, 38, 49, 65, 76, 97, 27, 49 };
    int low, high, mid;
    for (int i = 2; i <= 8; ++i){
        a[0] = a[i];
        low = 1;
        high = i - 1;
        while (low <= high){
            mid = (low + high) / 2;
            if (a[mid] > a[0]){
                high = mid - 1;
            }
            else{
                low = mid + 1;
            }
        }
        for (int j = i - 1; j >= high + 1; --j){
            a[j + 1] = a[j];
        }
        a[high + 1] = a[0];
    }
    int j = 0;
    while (j < 8){
        printf("%d ", a[j]);
        ++j;
    }
    return 0;
}

时间复杂度分析

  • 折半插入排序适合关键字数较多的场景,与直接插入排序相比,折半插入排序在查找插入位置上面所花的时间大大减少
  • 折半插入排序在关键字移动次数上面和直接插入排序是一样的,所以时间复杂度和直接插入排序还是一样的
  • 可知折半插入排序的时间复杂度最好情况为O(nlog2n),最差情况为O(n^2),平均情况为O(n^2)

空间复杂度分析

同直接插入排序,O(1)

希尔排序(缩小增量排序)

  • 将待排序列分成几个子序列,分别对这几个子序列进行直接插入排序
  • 如果增量是1,那么就是直接插入排序

该方法实质上是一种分组插入方法

  • 比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换

算法思想

  • 先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d
  • 对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序
  • 当增量减到1时,整个要排序的数被分成一组,排序完成

示例

  • 原始序列:49 38 65 97 76 13 27 45 55 04

  • 分割线指向的元素做直接插入排序
void ShellSort(int r[],int n){
    int i,j,d;
    int x;
    d=n/2;//d=n>>1
    while(d>=1){
        for(i=d ;i<n;i++){
            x=r[i];
             for(j=i-d;j>=0;j-=d){
                if(r[j]>x){
                    r[j+d]=r[j];
                }else{
                    break;
                }
            }
            r[j+d]=x;
         }//for i
       d>>=1;
      }//while
}//ShellSort

希尔排序不稳定

  • 增量序列的最后一个值一定取1
  • 增量序列中的值尽量没有除1之外的公因子

时间复杂度

  • 时间与步长选取有关,但目前没有对应解析表达式

空间复杂度O(1)

原文地址:https://www.cnblogs.com/YC-L/p/12689017.html

时间: 2024-08-05 07:04:31

八大排序之选择类排序的相关文章

15、排序:选择类排序和归并排序

代码更新自上篇,如下: 1 package ren.laughing.datastructure.algorithm; 2 3 import ren.laughing.datastructure.baseImpl.BinTreeNode; 4 5 /** 6 * 排序 7 * 8 * @author Laughing_Lz 9 * @time 2016年4月22日 10 */ 11 public class Sorter { 12 /** 13 * 直接插入排序(从小到大) 时间复杂度为O(n^

详谈排序算法之选择类排序(两种方法实现堆排序)

   今天我们再来讨论一下选择类排序,选择类排序分为:简单排序,树形选择排序和堆排序.但我们主要说的是简单和堆排序两个,因为树形选择排序使用了较多的辅助空间,以及和∞进行多余比较,为弥补树型选择排序的这些缺点, J.W.J.Williams 在 1964 年提出了进一步的改进方法,即堆排序.对于我个人而言..一开始并不是很理解它的算法思想,纠结了许久.在网上查找资料的时候发现这位大神的文章思路十分清晰,而且把创建堆以及堆化数组的算法讲解的十分详细.如果有不明白堆排序思路的,可以先看看这篇文章~堆

选择类排序总结

选择类排序总结 所谓选择类排序的思想就是:从数组的中选出最大或最小的,通过多次选择最后达到排序的目的 首先是简单选择排序 思想:每趟扫描中,选出最小的数字放在最前面,然后从第二个数字开始扫描,直到只剩下最后一个数不需要扫描 void EasySelect_Sort(int a[],int n) { int k; for(int i=1;i<n;i++) { k=i-1; for(int j=i;j<n;j++) { if(a[j]<a[k]) { k=j; } } if(k!=(i-1)

选择类排序

#include<stdio.h> /* *选择类排序,每天一道算法题 *按照从小到大的顺序进行排序 * */ //遍历序列 void traverseArray(int *p,int length) { int i=0; for(;i<length;i++) { printf("%d\n",p[i]); } } //简单选择类排序 void selectSort(int *p,int length) { int i,j,temp,index; for(i=0;i&l

选择类排序:选择排序,堆排序

选择类排序:1:简单选择排序O(n^2),空间O(1) 2:堆排序O(n乘以log以2为底,n的对数),空间复杂度O(1) //选择排序 void SelectSort(int R[],int n) { int i,j,k; int tmp; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) { if(R[j]<R[k]) k=j; } if(k!=i) { tmp=R[i]; R[i]=R[k]; R[k]=tmp; } } } //堆排序 vo

常见的五类排序算法图解和实现(多关键字排序:基数排序以及各个排序算法的总结)

基数排序思想 完全不同于以前的排序算法,可以说,基数排序也叫做多关键字排序,基数排序是一种借助“多关键字排序”的思想来实现“单关键字排序”的内部排序算法. 两种方式: 1.最高位优先,先按照最高位排成若干子序列,再对子序列按照次高位排序 2.最低位优先:不必分子序列,每次排序全体元素都参与,不比较,而是通过分配+收集的方式. 多关键字排序 例:将下表所示的学生成绩单按数学成绩的等级由高到低排序,数学成绩相同的学生再按英语成绩的高低等级排序.        第一个关键字是数学成绩,第二个关键字是英

详谈排序算法之插入类排序(两种思路实现希尔排序)

1. 排序( sorting) 的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列.其确切的定义为: 假设有n个数据元素的序列{R1 , R2 , - , Rn},其相应关键字的序列是{K1 , K2 , - , Kn} ,通过排序要求找出下标 1 , 2 , - , n的一种排列p1 , p2 , - , pn,使得相应关键字满足如下的非递减(或非递增)关系Kp1 ≤ Kp2 ≤ - ≤ Kpn这样,就得到一个按关键字有序的纪录序列{ Rp1 , Rp2 , - , Rpn }

数据结构 排序(选择排序)

//排序--选择排序法 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> /* 选择排序(Selection sort)是一种简单直观的排序算法. 它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素, 存放在序列的起始位置,直到全部待排序的数据元素排完. 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导

简单选择排序(选择排序)-八大排序三大查找汇总(1)

工作原理: 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 稳定性: 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面). 时间复杂度: 比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+...+1=n*(n-1)/2. 交换次数O(n),最好情况是,已经有序,交换0次:最坏情况下,即待排序记录初始状态是按第一条记录最大