排序算法学习整理二(选择)

9二、选择排序:

  选择排序十分的简单和直观,其的工作原理是每一次从待排序的数组中选出最小(或最大)的一个元素,存放在序列的起始位置。因此,选择排序也是像我们这种萌新最容易写出来的排序算法。

  排序步骤:

  1. 选出最小的元素
  2. 放在数组最前面
  3. 选出第二小的元素
  4. 放在第二位

  重复如此直到完成排序

  下面举个栗子:

    有一个数组其元素如下 5 1 4 3 2 6 7 0 9,其选择排序流程如下

  

   第一轮:      0 1 4 3 2 6 9 5 7    0最小,0和5换   第二轮:      0 1 4 3 2 6 9 5 7     1最小,不变   第三轮:      0 1 2 3 4 6 9 5 7    2最小,2和4换   第四轮:      0 1 2 3 4 6 9 5 7    3最小,不变   第五轮:      0 1 2 3 4 5 9 6 7    5最小,5和6换   第六轮:      0 1 2 3 4 5 6 9 7    6最小,6和9换   第七轮:      0 1 2 3 4 5 6 9 7    7最小,7和9换   第八轮:      0 1 2 3 4 5 6 9 7    已经完成排序,但任然需要比较

  从这个栗子,我们可以得出选择排序的核心代码:

  if (arr[min] > arr [j])
  {
      min = j;
  }
  arr[min] = arr[min] ^ arr[i];
  arr[i] = arr[min] ^ arr[i];
  arr[min] = arr[min] ^ arr[i];

  接着我们继续思考,两层for循环,首先是第一层,第一层循环有两个作用,第一个:从0~n-1一个个进行排序;二:表示需要比较的次数。由第一个作用我们可以知道第一层for循环的循环变量i<=n-1,由第二个作用可知i<n-1。(十个数比较只需要比较9次,且c的数组从0开始所以到9就是第十个元素,所以第九次比较就是当i=8的时候)由此可以得出第一层for的代码为 for (int i = 0; i < n-1; i++)。注:我们也可以从i = 1开始,略微改动一下循环终止条件就可以了。

  然后我们来确定一下第二层for循环,第二层for循环的作用很简单就是让当前元素与无序的元素进行比较,这里的难点在于无序的元素和当前元素的确定,让我们来回忆一下,第一层for循环的i是从0开始的那么我们的第二层for循环为了避免重复比较,所以第二层for循环的循环变量j应该从i+1开始,到哪里里终止呢?因为每一次都是把最下的元素放到最前面所以从 i 到 n-1都是无序元素,所以当j < n 时,进行循环。由此推出第二层循环 for (int j = i+1; j < n; j++)。如果一层for循环从1开始的,自行调整一下即可。

  至此我们就能写出完整的选择排序代码了。嗯?不对,还有个问题,我们的min该等于什么,嗯,没错,min = i,就可以了。

  好了现在我们开始写最后的代码吧

 1 void sort(int *arr, int count)
 2 {
 3     for (int i = 0; i < count-1; i++)
 4     {
 5         int min = i;
 6         for (int j = i+1; j < count; j++)
 7         {
 8             if (arr[min] > arr[j])
 9             {
10                 min = j;   //找到比arr[min]小的先不交换,先保留下标
11             }
12         }
13         if (min != i)   //为了避免arr[i],本身就是最小值任然进行交换的情况 。
14         {
15             arr[min] = arr[min] ^ arr[i];
16             arr[i] = arr[min] ^ arr[i];
17             arr[min] = arr[min] ^ arr[i];
18         }
19     }
20 }



  现在我们来想一想如何优化一下选择排序,其实很明显了,在交换方面我们已经没有办法优化了(至少对我这个蒟蒻来说)。那么我们来思考一下,选择排序每次选出最小的放在最前面,或者选出最大的放在最前。我们不仅可以选出最小的也可以选出最大,所以我们就在选出最小值的同时选出最大值,比较所消耗的时间要比循环少,略有优化。

  按照这个思想可以写出代码如下:

 1 void sort(int *arr, int count)
 2 {
 3     int left = 0;
 4     int right = count-1;
 5     int min = left;
 6     int max = right;
 7
 8     while (left < right)
 9     {
10         min = left;
11         max = left;
12         for (int i = left; i <= right; i++)
13         {
14             if (arr[min] > arr[i])
15             {
16                 min = i;
17             }
18             if (arr[max] < arr[i])
19             {
20                 max = i;
21             }
22         }
23
24         if (left != min)    //最小交换
25         {
26             arr[min] = arr[min] ^ arr[left];
27             arr[left] = arr[min] ^ arr[left];
28         }
29
30         if (max == left)    //防止当min最小,max最大时产生连续交换
31         {
32             max = min;
33         }
34
35         if (right != max)   //最大交换
36         {
37             arr[max] = arr[max] ^ arr[right];
38             arr[right] = arr[max] ^ arr[right];
39             arr[max] = arr[max] ^ arr[right];
40         }
41         left++;
42         right--;
43     }
44 }

  这里要特别说明一下这段代码

        if (max == left)
        {
            max = min;
        }

  为什么一定要写这段代码呢,

  我们 来看个例子 :

    有个数组其元素为 9 1 5 6 0;

      max = 0,min = 4;

    执行min交换后,0 1 5 6 9;

      max = 0,min = 4;

    这时候如果执行max循环那么,数组就和没有执行min交换一样

所以为了防止出现这种情况就需要加上这块代码。

  目前作为蒟蒻的我只能优化到这里,如果有更好的优化,大家自行探索,我也会慢慢学习,继续更新。

原文地址:https://www.cnblogs.com/daker-code/p/10328571.html

时间: 2024-10-14 01:14:41

排序算法学习整理二(选择)的相关文章

排序算法学习整理三(插入)

三.插入排序: 插入排序是一种非常简单的排序,它的实现难度低于冒泡和选择.(我第一个for循环写出的排序就是插入排序)插入排序类似整理扑克牌,将每一张牌插到其他已经有序的牌中适当的位置. 基本思想: 插入排序由N-1趟排序组成,对于P=1到N-1趟,插入排序保证从位置0到位置P上的元素为已排序状态. 简单的说,就是插入排序总共需要排序N-1趟,从Index为1开始,讲该位置上的元素与之前的元素比较,放入合适的位置,这样循环下来之后,即为有序数组. 代码实现 1 void insertionSor

排序算法学习之堆排序

一.堆与堆排序的产生及定义 在简单选择排序中,每次从n个元素中比较n-1次选取最小的元素,这很好理解,但是前面比较过的数据在之后还要重新比较,这将花费大量的运算时间.堆排序算法就很好的解决了这个问题,堆排序在每次选择到最小记录的同时会根据比较结果对其他数据进行调整,堆排序的时间复杂度为O(NlogN). 堆通常是指二叉堆,即堆是一颗完全二叉树,同时其满足一定性质:每个节点的值大于等于其左右孩子的值(大顶堆),或者每个节点的值小于等于其左右孩子的值(小顶堆).堆在本质上是一个数组,根节点即为a[0

时间/空间复杂度,基础排序算法(冒泡、选择、快速、插入)

一.时间复杂度.空间复杂度 时间复杂度:用来评估算法运行效率的一个东西,用O()来表示 举例时间复杂度计算: print('Hello World') O(1) for i in range(n): #n次循环 print('Hello World') O(n) for i in range(n): for j in range(n): #两个n嵌套循环 print('Hello World') O(n²) 以下这些代码时间复杂度呢? print('Hello World') print('He

若干排序算法简单汇总(二)

转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/36706131 作者:小马 一希尔排序 上一篇讲到的直接插入排序,时间复杂度O(n^2). 请在脑海里想一下它的过程.如果一个序列本来就是有序的,对它排序的时间复杂度是O(n).所以当序列基本有序时,插入排序排序的效率大大提高,因为减少了移动的动作. 另外,直接插入排序还有一个特点,当n比较小时,它的效率比较高. 希尔排序正是基于上面两个思想做的一种改进算法.它先将整个序列分成若干

八大排序算法学习笔记:插入排序(一)

插入排序     包括:直接插入排序,二分插入排序(又称折半插入排序),链表插入排序,希尔排序(又称缩小增量排序).属于稳定排序的一种(通俗地讲,就是两个相等的数不会交换位置) . 直接插入排序: 1.算法的伪代码(这样便于理解):     INSERTION-SORT (A, n)             A[1 . . n] for j ←2 to n do key ← A[ j] i ← j – 1 while i > 0 and A[i] > key do A[i+1] ← A[i]

javascript 基础学习整理 二 之 html对象总结,参考W3C

Anchor 对象 更改一个链接的文本.URL 以及 target 使用 focus() 和 blur() 向超链接添加快捷键 Document 对象 使用 document.write() 向输出流写文本 使用 document.write() 向输出流写 HTML 返回当前文档的标题 返回当前文档的 URL 返回当前文档的 referrer 返回下载当前文档的服务器域名 使用 getElementById() 使用 getElementsByName() 打开一个新的文档,添加一些文本,然后

【数据结构】——排序算法——3.1、选择排序

      [数据结构]--排序算法--3.1.选择排序 一.先上维基的图: 分类 排序算法 数据结构 数组 最差时间复杂度 О(n2) 最优时间复杂度 О(n2) 平均时间复杂度 О(n2) 最差空间复杂度 О(n) total, O(1)auxiliary 二.描述: 选择算法算是最直观的一个了.每次在队列里抽取一个极大(或极小)值进行排列.每次都需要遍历未被抽取的元素队列. 三.Java程序: static void selection_sort(int[] unsorted) { for

AJAX学习整理二之简单实例

做了几个简单的实例,加载txt文本内容.加载xml文件内容,把xml文本内容转换成html表格显示.废话不多说,直接贴代码: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/html"> <head>     <title>通过ajax获取文本内容</title>     <meta charset="utf-8">     <scr

常见排序算法(冒泡、选择、插入、快速、归并C++实现)

常见排序算法(冒泡.选择.插入.快速.归并C++实现) #include <iostream> using namespace std; // 冒泡排序 void bubbleSort (int data[], size_t size) { for (size_t i = 0; i < size - 1; ++i) { bool ordered = true; for (size_t j = 0; j < size - 1 - i; ++j) if (data[j+1] <