手撕排序算法2:堆排序和直接选择排序(下)

简介: 手撕排序算法2:堆排序和直接选择排序(下)

二.直接选择排序

1.算法剖析

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

代码实现

void SelectSort(int* a, int n)
{
  int i = 0;
  for (i = 0; i < n; i++)//i:排好序的元素的最大下标
  {
    int j = 0;
    int min = i;//从i下标位置开始选出最小值
    for (j = i; j < n; j++)
    {
      if (a[min] > a[j])//更新最小值
      {
        min = j;
      }
    }
    Swap(&a[min], &a[i]);//把最小值放在i下标位置处
  }
}

可见,时间复杂度是O(N^2),

而且,需要注意的是直接选择排序的双层for循环中并没有出现break

也就是说无论待排序的序列是有序还是无序还是部分有序

直接选择排序并不考虑这些,它是找最大值(或者最小值)依次放到数组的起始位置

2.优化版本算法剖析

上面代码不难理解,下面我们来给大家看一个优化版本的直接选择排序,这个优化版本比上一个版本快一倍,不过时间复杂度也是O(N^2)

void Swap(int* n1, int* n2)
{
  int tmp = *n1;
  *n1 = *n2;
  *n2 = tmp;
}
void SelectSort(int* a, int n)
{
  int begin = 0;
  int end = n - 1;
  while (begin < end)
  {
    int min_i = begin;
    int max_i = begin;
    for (int i = begin; i <= end; i++)
    {
      if (a[i] < a[min_i])
      {
        min_i = i;
      }
      if (a[i] > a[max_i])
      {
        max_i = i;
      }
    }
    Swap(&a[begin], &a[min_i]);
    //如果begin跟max_i重叠,需要修正一下max_i的位置
    if (begin == max_i)
    {
      max_i = min_i;
    }
    Swap(&a[max_i], &a[end]);
    begin++;
    end--;
  }
}

这个优化版本的思想是:

1.通过begin和end逐步缩小待排序的范围,当begin>=end时,排序完成

2.通过min_i和max_i选择出[begin,end]内的最大值和最小值,并把最小值与begin位置处的数据交换,把最大值与end位置处的数据交换.

下面是不修正max_i的代码

void Swap(int* n1, int* n2)
{
  int tmp = *n1;
  *n1 = *n2;
  *n2 = tmp;
}
void SelectSortUpper(int* a, int n)
{
  int begin = 0;
  int end = n - 1;
  while (begin < end)
  {
    int min_i = begin;
    int max_i = begin;
    int i = 0;
    for (i = begin; i <= end; i++)
    {
      if (a[min_i] > a[i])
      {
        min_i = i;
      }
      if (a[max_i] < a[i])
      {
        max_i = i;
      }
    }
    Swap(&a[min_i], &a[begin]);
    Swap(&a[max_i], &a[end]);
    begin++;
    end--;
  }
}

下面给大家画图解释一下为什么要修正max_i的位置

3.时间复杂度和稳定性

1.时间复杂度

直接选择排序的时间复杂度是O(N^2)

都是等差数列

未优化版本:

N+(N-1)+(N-2)+… -> O(N^2)

优化版本

N+(N-2)+(N-4)+… -> O(N^2)

2.对直接选择排序的评价

在这里我们可以看出:插入排序为1698ms,直接选择排序为4533ms,同样时间复杂度都是O(N^2),但是却相差这么大,

所以也就是说直接选择排序效率非常差,是效率最差的排序算法,

后面讲到冒泡排序(时间复杂度也是O(N^2))的时候我们还要再对比一下这三者的时间复杂度.

3.稳定性

直接选择排序不具有稳定性,下面给大家举一个例子

以上就是堆排序和直接选择排序的讲解,希望能给大家带来帮助

相关文章
|
13天前
|
算法 Python
数据结构算法--4堆排序
堆排序过程概述:建立大根堆,将堆顶最大元素移出并替换为末尾元素,调整保持堆性质,重复此过程直至堆为空,实现排序。时间复杂度为O(nlogn)。Python中可用heapq模块进行堆操作。
|
7天前
|
搜索推荐 算法 Java
Java数据结构与算法:排序算法之选择排序
Java数据结构与算法:排序算法之选择排序
|
7天前
|
算法 搜索推荐 Java
Java数据结构与算法:排序算法之堆排序
Java数据结构与算法:排序算法之堆排序
|
13天前
|
搜索推荐 算法 Java
Java中的快速排序、归并排序和堆排序是常见的排序算法。
【6月更文挑战第21天】Java中的快速排序、归并排序和堆排序是常见的排序算法。快速排序采用分治,以基准元素划分数组并递归排序;归并排序同样分治,先分割再合并有序子数组;堆排序通过构建堆来排序,保持堆性质并交换堆顶元素。每种算法各有优劣:快排平均高效,最坏O(n²);归并稳定O(n log n)但需额外空间;堆排序O(n log n)且原地排序,但不稳定。
19 3
|
13天前
|
机器学习/深度学习 算法 搜索推荐
数据结构算法--2 冒泡排序,选择排序,插入排序
**基础排序算法包括冒泡排序、选择排序和插入排序。冒泡排序通过相邻元素比较交换,逐步将最大值“冒”到末尾,平均时间复杂度为O(n^2)。选择排序每次找到剩余部分的最小值与未排序部分的第一个元素交换,同样具有O(n^2)的时间复杂度。插入排序则类似玩牌,将新元素插入到已排序部分的正确位置,也是O(n^2)复杂度。这些算法适用于小规模或部分有序的数据。**
|
17天前
|
搜索推荐
排序算法---选择排序-----详解&&代码
排序算法---选择排序-----详解&&代码
|
23天前
|
算法 搜索推荐
数据结构与算法-选择排序
数据结构与算法-选择排序
13 4
|
10天前
|
搜索推荐 算法
【C/排序算法】:堆排序和选择排序
【C/排序算法】:堆排序和选择排序
9 0
|
27天前
|
算法 搜索推荐 Java
JavaSE——算法(1/2):认识、冒泡排序、选择排序及优化(介绍、详细图解、代码)
JavaSE——算法(1/2):认识、冒泡排序、选择排序及优化(介绍、详细图解、代码)
20 0
|
28天前
|
存储 算法 C语言
数据结构和算法——堆排序(选择排序、思路图解、代码、时间复杂度、堆排序及代码)
数据结构和算法——堆排序(选择排序、思路图解、代码、时间复杂度、堆排序及代码)
16 0