C++插入排序算法实例详解

本文实例为大家分享了C++插入排序算法实例的具体代码,供大家参考,具体内容如下

基本思想

每次将一个待排序的元素,按其大小插入到已经排好序的子序列的适当位置,知道全部元素插入完成为止。

直接插入排序

1.排序思路

arr[0...i-1]为有序区(刚开始时i=1,有序区只有arr[0]一个元素),arr[i...size]为待排序区,每次将待排序区的第一个元素arr[i]插入到有序区中的适当位置,每趟操作都使有序区增加一个元素,待排序区减少一个元素。

2.排序算法

void InsertSort(int* arr, int size)
{
  if (arr == NULL)
    return; 

  for (int i = 1; i < size; i++)
  {
    //1.保存要排序的数
    int tmp = arr[i];
    //2.去有序区寻找该数应该插入的位置
    int j = i - 1;
    while (j >= 0 && tmp < arr[j])
    {
      //3.把有序区的位置一个一个往后移
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = tmp;
  }
}

3.算法分析

直接插入排序由两重循环构成,外循环进行n-1次。
若初始数据序列递增有序即为正序时,每一趟排序不进入内循环,仅进行一次大小比较。此时元素移动次数为2次(tmp = arr[i]和arr[j+1] = tmp)。所以正序时比较次数和元素移动次数均达到最小值Cmin和Mmin:

Cmin = n-1
Mmin = 2(n-1)

若初始数据序列递减有序即为逆序时,因当前有序区的元素均大于待排序区的元素,所以需要将待插入元素与arr[0...i-1]中全部元素进行比较,这需要进行i次比较;内循环中需将arr[0...i-1]中所有元素后移(i-1)-0+1 = i次,外加tmp = arr[i]和arr[j+1] = tmp的两次移动,一趟排序所需的元素移动次数为i+2次。所以逆序时比较次数和元素移动次数均达到最da值Cmax和Mmax:

Cmax = n(n-1) / 2
Mmax = (n-1)(n+4) / 2

正序时直接插入排序算法的时间复杂度为O(N),逆序时直接插入排序算法的时间复杂度为O(N^2)。
故直接插入排序算法的时间复杂度为O(N^2)。由于只使用了i、j、tmp三个辅助变量,故空间复杂度为O(1)。
当i > j且arr[i] = arr[j]时,直接将arr[i]插入到arr[j]后,故直接插入排序是稳定的。

折半插入排序(二分插入排序)

1.排序思路

采用折半查找方法先在arr[0...i-1]中找到插入位置,再通过移动元素进行插入
2.排序算法

void InsertSort1(int* arr, int size)
{
  if (arr == NULL)
    return; 

  int i, j, low, high;
  //1.保存要插入的数
  for (i = 1; i < size; i++)
  {
    int tmp = arr[i];
    low = 0;
    high = i - 1;
    //2.折半查找插入位置(插入位置为high+1)
    while (low <= high)
    {
      int mid = low + ((high - low) >> 1);
      if (tmp < arr[mid])
        high = mid - 1;
      else
        low = mid + 1;
    }
    //3.元素后移,插入
    for (j = i - 1; j >= high + 1; j--)
    {
      arr[j + 1] = arr[j];
    }
    arr[j + 1] = tmp;
  }
}

3.算法分析

当初始数据序列为正序时,比较次数并不能减少;当为逆序时,比较次数也不会增加。元素移动次数与直接插入排序相同。
故折半插入排序的时间复杂度为O(N^2),空间复杂度为O(1),是稳定的。
就平均性能而言,折半查找优于顺序查找,所以折半插入排序优于直接插入排序。

希尔排序

1.排序思路

希尔排序是一种分组插入排序。先取一个小于n的整数d1,作为第一个增量,序列被分为d1组,所有相互之间距离为d1的倍数的元素放在同一个组中,在各组内进行直接插入排序;然后取第二个增量d2(<d1),重复上述过程,直至增量为1。
希尔排序每趟并不产生有序区,在最后一趟排序结束之前,所有元素并不一定归位,每趟排完之后,数据越来越接近有序。

2.排序算法

void ShellSort(int* arr, int size)
{
  if (arr == NULL)
    return; 

  int i, j, gap;
  //1.取gap
  gap = size / 2;
  while (gap > 0)
  {
    //2.分组比较
    for (i = gap; i < size; i++)
    {
      int tmp = arr[i];
      //3.移动元素,插入
      j = i - gap;
      while (j >= 0 && tmp < arr[j])
      {
        arr[j + gap] = arr[j];
        j -= gap;
      }
      arr[j + gap] = tmp;
    }
    gap = gap / 2;
  }
}

3.算法分析

希尔排序算法的性能分析是一个复杂的问题,它的时间复杂度与所取gap有关,一般认为其时间复杂度为O(N^1.3),空间复杂度为O(1)。
希尔排序是一种不稳定的算法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android Java调用自己C++类库的实例讲解

    Android Java 如何调用自己的 C++ 的类库 下面以 Java 调用 C++ 的加法运算函数为例,做简单说明. (使用 Android Studio 3 编译) 首先编译 c++ 类库 创建独立目录存放 c++ 文件,例如 "app/src/main/cpp/add.cpp",内容如下 #include <jni.h> extern "C" JNIEXPORT jint JNICALL Java_com_example_liyi_demo_U

  • C++小知识:用++i替代i++

    静态代码分析工具可简化编码过程,检测出错误并帮助修复.PVS-Studio 是一个用于 C/C++ 的静态代码分析工具.该团队检测了 200 多个 C/C++ 开源项目,包括了 Unreal Engine.Php.Haiku.Qt 和 Linux 内核等知名项目.于是他们每天分享一个错误案例,并给出相应建议. 这个 bug 是在 Unreal Engine 4 的源代码中发现的. 错误代码: void FSlateNotificationManager::GetWindows( TArray<

  • C++实现洗牌发牌排序功能的示例代码

    在内存中模拟出一副牌,然后模拟洗牌,发牌等动作. 流程是这样的:构建一副牌保存到一个数组中-洗牌-创建玩家-向玩家发牌–输出每个玩家的牌. #include <stdio.h> #include <stdlib.h> #include <time.h> //定义扑克的花色 enum Suit{ heart, spade, diamond, club, joker1, joker2 }; //一副牌的数量 #define CARD_COUNT 54 //定义扑克 type

  • C++选择排序算法实例详解

    本文实例为大家分享了C++选择排序算法的具体代码,供大家参考,具体内容如下 基本思想 每一趟从无序区中选出最小的元素,顺序放在有序区的最后,直到全部元素排序完毕. 由于选择排序每一趟总是从无序区中选出全局最小(或最大)的元素,所以适用于从大量元速度中选择一部分排序元素.例如,从10000个元素中选出最小的前10位元素. 直接选择排序 1.排序思路 从第i趟开始,从当前无序区arr[i-n-1]中选出最小元素arr[k],将它与有序区的最后一个元素,也就是无序区的第一个元素交换.每趟排序后,有序区

  • C++实践排序函数模板项目的参考方法

    [项目-排序函数模板] 已知 void Sort(int a[],int size); void Sort(double a[],int size); 是一个函数模板的两个实例,其功能是将数组a中的前size个元素按从小到大顺序排列.试设计这个函数模板. 参考解答: #include<iostream> using namespace std; template<class T> void Sort(T set[],int n) { int i,j; T temp; for(i=1

  • C++小知识:用合适的工具来分析你的代码

    静态代码分析工具可简化编码过程,检测出错误并帮助修复.有个国外团队检测了 200 多个 C/C++ 开源项目,包括了 Php.Qt 和 Linux 内核等知名项目.于是他们每天分享一个错误案例,并给出相应建议.今天的案例来自 LibreOffice 项目. 错误代码 BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { .... CreateThread( NULL, 0, ParentM

  • Python使用ctypes调用C/C++的方法

    python使用ctypes调用C/C++ 1. ctpes介绍 ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python. 官方文档地址: https://do

  • C++二维数组中数组元素存储地址的计算疑问讲解

    关于二维数组中数组元素的存储地址,有同学问出了个好问题. 在我的课件中,出现了下面的讲解: a[i][j]的地址是p+(i*col+j)*d(d是数组元素所占的字节数). 同学编程序进行验证,出问题了: 地球停止转动了也必须先赞这种学习方式! 同学问:"老师,第一张图的4,我怎么觉得不对呢?第二张图我没4,结果好像也对,这里面差在哪呢?" 我的答复:"两个都对." 第一张图在讲原理,是我们在人脑里面要以"字节"为单位计算,p为首地址,单位是字节,

  • C++小知识:不要去做编译器的工作

    对于C++编程的老鸟来说,有时候他们喜欢把一些东西按照编译器的工作原理进行改写,以便提高代码的运行效率.这么做确实高明,也能体现出程序员的水平,但是这么做也是有风险的.因为有时候你可能会因为一些简单的笔误,而造成非常难以察觉的错误.本文就给出了类似的例子. 这个Bug 出现在MySQL源代码中. 错误代码: static int rr_cmp(uchar *a,uchar *b) { if (a[0] != b[0]) return (int) a[0] - (int) b[0]; if (a[

  • 剑指offer之C++语言实现链表(两种删除节点方式)

    1 问题 用C++语言实现链表 2 代码实现 #include <iostream> #include <stdlib.h> using namespace std; class List { public: List(); ~List(); List* createNode(int value);//创建节点 bool insertNode(List *node);//插入节点 void printList();//打印节点 bool deleteNode(List *node)

随机推荐