常见的七种排序算法(一)

简介: 常见的七种排序算法

1.排序算法的概念及其运用


1.1 排序的概念


* 排序: 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列     起来的操作。


* 稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这 些记   录的相对次 序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列 中,r[i]仍在r[j]之前,则称这种排 序算法是稳定的;否则称为不稳定的。


* 时间复杂度:排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。


* 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。


* 内部排序:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。


* 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

1.2 排序运用


 像淘宝商品价格排序,各个学校的综合评分排名等,都运用了排序算法相关的知识.

image.png

1.3 常见的排序算法


image.png

2.常见排序算法的实现


2.1 插入排序


   基本思想

 直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一 个已经排好序的有序序列中,直到所有

void InsertSort(int* a, int n)
{
    //n:待排序数字的个数;n=sizeof(a)/sizeof(int);
  assert(a);//函数断言
  for (int i = 0; i < n - 1; ++i)
  {
    // 将x插入[0, end]有序区间
    int end = i;
    int x = a[end+1];
    while (end >= 0)
    {
      if (a[end] > x)
      {
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = x;
  }
}

的记录插入完为止,得到一个新的有序      序 列实际中我们玩扑克牌时,就用了插入排序的思想.

image.png

2.1.1 直接插入排序  


   * 从第一个元素开始,该元素可以认为已经被排序;

   * 取出下一个元素,在已经排序的元素序列中从后向前扫描;

   * 如果该元素(已排序)大于新元素,将该元素移到下一位置;

   * 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;

   * 将新元素插入到该位置后;

   * 重复步骤2~5。

 动图演示:    

09caf3b951fb4724bb4bbf4fda1b4387.gif

  代码实现:

void InsertSort(int* a, int n)
{
    //n:待排序数字的个数;n=sizeof(a)/sizeof(int);
  assert(a);//函数断言
  for (int i = 0; i < n - 1; ++i)
  {
    // 将x插入[0, end]有序区间
    int end = i;
    int x = a[end+1];
    while (end >= 0)
    {
      if (a[end] > x)
      {
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = x;
  }
}

    直接插入排序特性总结:

  1.元素集合越接近有序,直接插入排序算法的时间效率越高;

   2. 时间复杂度:O(N^2) ;

   3. 空间复杂度:O(1),它是一种稳定的排序算法 ;

   4. 稳定性:稳定;

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


希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所 有记录分成个 组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后 取, 重复上述分组和排序的工 作。当到达=1时,所有记录在统一组内排好序。

image.png

 动图演示:

image.gif

   代码实现:

void ShellSort(int* a, int n)
{
    //n:待排序数字的个数;n=sizeof(a)/sizeof(int);
  // 多次预排序(gap > 1) +直接插入 (gap == 1)
  int gap = n;
  while (gap > 1)
  {
    //gap = gap / 2;
    gap = gap / 3 + 1;
    // 多组并排
    for (int i = 0; i < n - gap; ++i)
    {
      int end = i;
      int x = a[end + gap];
      while (end >= 0)
      {
        if (a[end] > x)
        {
          a[end + gap] = a[end];
          end -= gap;
        }
        else
        {
          break;
        }
      }
      a[end + gap] = x;
    }
  } 
}

   希尔排序的特性总结:

   1. 希尔排序是对直接插入排序的优化。

   2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的      了,这样就 会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对      比。

   3. 希尔排序的时间复杂度不好计算,需要进行推导,推导出来平均时间复杂度: O(N^1.3—          N^2)

   4. 稳定性:不稳定

2.2 选择排序


   基本思想:

   每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,      直到 全部待排序的数据元素排完

2.2.1 直接选择排序


n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

  * 初始状态:无序区为R[1..n],有序区为空;

  * 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当     前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和   R[i+1..n)   分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;

  * n-1趟结束,数组有序化了。

image.png

 动图演示:

a9dfb44aedb8400182d2a9131a6ef713.gif

   代码实现:

void swap(int* a, int* b)
{
  int temp = *a;
  *a = *b;
  *b = temp;
}
void selectsort(int* a, int n)
{
  assert(a);
  for (int i = 0; i < n - 1; i++)
  {
    int min = i;
    for (int j = i + 1; j < n; j++)
    {
      if (a[j] < a[min])
        min = j;
    }
    swap(&a[min], &a[i]);
  }
}

  直接选择排序的特征总结:

   1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

   2. 时间复杂度:O(N^2)

   3. 空间复杂度:O(1)

   4. 稳定性:不稳定

2.2.2 堆排序


堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

54286d5421514bc79fce56a177692dc9.png

动图演示:

image.gif

代码演示:

void Adjustdown(int* a,int n,int parent)
{
  int child = parent * 2 + 1;
  while (child < n)
  {
    if (child + 1 < n && a[child + 1] > a[child])
    {
      child++;
    }
    if (a[child] > a[parent])
    {
      swap(&a[child], &a[parent]);
      parent = child;
      child = parent * 2 + 1;
    }
    else {
      break;
    }
  }
}
void heapsort(int* a, int n)
{
  assert(a);
  for (int i = (n - 1 - 1) / 2; i >= 0; i--)
  {
    Adjustdown(a, n, i);
  }
  int end = n - 1;
  while (end >= 0)
  {
    swap(&a[end], &a[0]);
    Adjustdown(a, end, 0);
    end--;
  }
}

  堆排序的特征总结:

   1. 堆排序使用堆来选数,效率就高了很多。

   2. 时间复杂度:O(N*logN)

   3. 空间复杂度:O(1)

   4. 稳定性:不稳定

相关文章
|
7月前
|
搜索推荐 C++
7大排序算法C++实现
7大排序算法C++实现
72 0
|
3月前
|
搜索推荐 索引
排序算法详解
本文介绍了多种排序算法,包括插入排序(如直接插入排序和希尔排序)、选择排序(如直接选择排序和堆排序)、交换排序(如冒泡排序和快速排序)以及归并排序和计数排序。插入排序通过构建有序序列逐步插入元素;选择排序通过不断选择最小元素放置于序列起始;交换排序通过元素间的交换达到排序目的;归并排序采用分治法将序列分解再合并;计数排序则通过统计元素出现次数来排序。文章详细阐述了各种排序算法的原理及其实现方法。
48 6
|
7月前
|
搜索推荐 算法
常见的排序算法(1)
常见的排序算法(1)
85 3
|
7月前
|
搜索推荐 C#
C#实现选择排序算法
C#实现选择排序算法
51 2
|
7月前
|
搜索推荐 算法 NoSQL
10-千奇百怪的排序算法
10-千奇百怪的排序算法
|
搜索推荐 算法
14 排序算法
14 排序算法
33 0
|
算法 搜索推荐 Java
TimSort——最快的排序算法
TimSort 算法是 Tim Peters 于 2001 年为 Python 语言创建的。该算法建立在插入排序和归并排序的基础之上,兼具插入排序和归并排序的优点。TimSort 的平均时间复杂度为 O(nlog(n)) ,最好情况 O(n) ,最差情况 O(nlog(n)) 。空间复杂度 O(n) ,是一个稳定的排序算法。
1619 0
TimSort——最快的排序算法
|
算法 搜索推荐 Java
常见排序算法详解(1)
前言 排序是我们在日常生活和工作中常见的一种操作。在计算机科学中,排序算法就是将一串或一组数据按照特定的顺序进行排列的算法。这些顺序可能是数字的升序或降序,也可能是字母或字词的字母顺序等。我们将探讨几种不同的排序算法,包括他们的原理、优缺点以及代码实现。
143 0
|
存储 算法 搜索推荐
【C++】常见的几种排序算法
【C++】常见的几种排序算法
73 0
|
搜索推荐
带你了解排序算法
带你了解排序算法
139 0
带你了解排序算法