内部排序算法:直接选择排序

基本思想

n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:

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

这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。

算法实现

直接选择排序算法,Java实现,代码如下所示:

01 public abstract class Sorter {
02 public abstract void sort(int[] array);
03 }
04
05 public class StraightSelectionSorter extends Sorter {
06
07 @Override
08 public void sort(int[] array) {
09 int tmp; // 用于交换数据的暂存单元
10 for (int i = 0; i < array.length - 1; i++) { // 这里只要从0~array.length-2即可
11 int k = i;
12 for (int j = i + 1; j < array.length; j++) { // 该循环可以找到右侧无序区最小的元素array[k]
13 if (array[k] > array[j]) {
14 k = j;
15 }
16 }
17 if (k != i) { // 如果array[i]不是无序区最小的,需要与无序区最小的进行交换
18 tmp = array[i];
19 array[i] = array[k];
20 array[k] = tmp;
21 }
22 // 如果array[i]是无序区最小的元素,不需要执行交换
23 }
24 }
25 }

直接选择排序算法,Python实现,代码如下所示:

01 class Sorter:
02 '''
03 Abstract sorter class, which provides shared methods being used by
04 subclasses.
05 '''
06 __metaclass__ = ABCMeta
07
08 @abstractmethod
09 def sort(self, array):
10 pass
11
12 class StraightSelectionSort(Sorter):
13 '''
14 Straight selection sorter
15 '''
16 def sort(self, array):
17 i = 0
18 length = len(array)
19 while i<length -1:
20 k = i
21 j = i
22 while j<length:
23 if array[j]<array[k]:
24 k = j
25 j = j + 1
26 if k!=i:
27 array[k], array[i] = array[i], array[k]
28 i = i + 1

排序过程

首先,从0~n-1个元素中找到最小的元素,交换到0位置上;
其次,再从1~n-1中找到次最小的元素,交换到1位置上;
……;
最后从n-2~n-1中找到最小的元素,交换到n-2位置上。n-1位置上一定是最大的元素,所以总共进行n-1趟选择排序。
需要注意的是:
每次确定无序区后,其中除了第一个元素之外的其它元素(设为e)与第一个元素(设为E)比较,只有满足e<E的时候才需要交换一次。

排序过程示例如下:
假设待排序数组为array = {94,12,34,76,26,9,0,37,55,76,37,5,68,83,90,37,12,65,76,49},数组大小为20。

  • 第1趟选择排序

从array[1,n-1]中找到最小的元素:
array[0] = 94>array[1] = 12,交换array[0]与array[1],即array[0] = 12array[2] = 34不成立,不交换;
array[0] = 12>array[3] = 76不成立,不交换;
array[0] = 12>array[4] = 26不成立,不交换;
array[0] = 12>array[5] = 9,交换array[0]与array[5],即array[0] = 9array[6] = 0,交换array[0]与array[6],即array[0] = 0array[7] = 37不成立,不交换;
array[0] = 0>array[8] = 55不成立,不交换;
array[0] = 0>array[9] = 76不成立,不交换;
array[0] = 0>array[10] = 37不成立,不交换;
array[0] = 0>array[11] = 5不成立,不交换;
array[0] = 0>array[12] = 68不成立,不交换;
array[0] = 0>array[13] = 83不成立,不交换;
array[0] = 0>array[14] = 90不成立,不交换;
array[0] = 0>array[15] = 37不成立,不交换;
array[0] = 0>array[16] = 12不成立,不交换;
array[0] = 0>array[17] = 65不成立,不交换;
array[0] = 0>array[18] = 76不成立,不交换;
array[0] = 0>array[19] = 49不成立,不交换。
此时数组状态如下:{0,94,34,76,26,12,9,37,55,76,37,5,68,83,90,37,12,65,76,49}。
此时,有序区为{0},无序区为{94,34,76,26,12,9,37,55,76,37,5,68,83,90,37,12,65,76,49}。

  • 第2趟选择排序

从array[2,n-1]中找到最小的元素:
array[1] = 94>array[2] = 34,交换array[1]与array[2],即array[1] = 34array[3] = 76不成立,不交换;
array[1] = 34>array[4] = 26,交换array[1]与array[4],即array[1] = 26array[5] = 12,交换array[1]与array[5],即array[1] = 12array[6] = 9,交换array[1]与array[6],即array[1] = 9array[7] = 37不成立,不交换;
array[1] = 0>array[8] = 55不成立,不交换;
array[1] = 0>array[9] = 76不成立,不交换;
array[1] = 0>array[10] = 37不成立,不交换;
array[1] = 9>array[11] = 5,交换array[1]与array[11],即array[1] = 5array[12] = 68不成立,不交换;
array[1] = 5>array[13] = 83不成立,不交换;
array[1] = 5>array[14] = 90不成立,不交换;
array[1] = 5>array[15] = 37不成立,不交换;
array[1] = 5>array[16] = 12不成立,不交换;
array[1] = 5>array[17] = 65不成立,不交换;
array[1] = 5>array[18] = 76不成立,不交换;
array[1] = 5>array[19] = 49不成立,不交换。
此时数组状态如下:{0,5,94,76,34,26,12,37,55,76,37,9,68,83,90,37,12,65,76,49}。
此时,有序区为{0,5},无序区为{94,76,34,26,12,37,55,76,37,9,68,83,90,37,12,65,76,49}。

  • 第3趟选择排序

排序后数组状态为:{0,5,9,94,76,34,26,37,55,76,37,12,68,83,90,37,12,65,76,49}。
此时,有序区为{0,5,9},无序区为{94,76,34,26,37,55,76,37,12,68,83,90,37,12,65,76,49}。

  • 第4趟选择排序

排序后数组状态变化:
{0,5,9,76,94,34,26,37,55,76,37,12,68,83,90,37,12,65,76,49},
{0,5,9,34,94,76,26,37,55,76,37,12,68,83,90,37,12,65,76,49},
{0,5,9,26,94,76,34,37,55,76,37,12,68,83,90,37,12,65,76,49},
{0,5,9,12,94,76,34,37,55,76,37,26,68,83,90,37,12,65,76,49},
{0,5,9,12,94,76,34,37,55,76,37,26,68,83,90,37,12,65,76,49},
此时,有序区为{0,5,9,12},无序区为{94,76,34,37,55,76,37,26,68,83,90,37,12,65,76,49}。
……

  • 第n-1趟选择排序

依此类推,执行n-1趟选择排序,最后得到:有序区为{0,5,9,12,12,26,34,37,37,37,49,55,65,68,76,76,76,83,90},无序区为{94},此时整个数组已经有序,n-1趟选择排序后,排序完成。

算法分析

  • 时间复杂度
  1. 记录比较次数:

无论待排序数组初始状态如何,都要进行n-1趟选择排序:

  • 第1趟:比较n-1次;
  • 第2趟:比较n-2次;
  • ……
  • 第n-1趟:比较1次。

从而,总共的比较次数为:1+2+……+(n-1) = n(n-1)/2

记录移动次数:

如果待排序数组为正序,则记录不需要交换,记录移动次数为0;
如果当排序数组为逆序,则:

  • 第1趟:交换1次,移动3次;
  • 第2趟:交换1次,移动3次;
  • ……
  • 第n-1趟:交换1次,移动3次。

从而,总共的移动次数为:3(n-1) = 3(n-1)。
因此,时间复杂度为O(n2)。

  • 空间复杂度

在选择排序的过程中,设置一个变量用来交换元素,所以空间复杂度为O(1)。

排序稳定性

选择排序是就地排序。
通过上面的排序过程中数组的状态变化可以看出:直接选择排序是不稳定的。

时间: 2024-11-01 21:37:54

内部排序算法:直接选择排序的相关文章

我的Java开发学习之旅------&amp;gt;Java经典排序算法之选择排序

一.算法原理 对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置, 接着第二次比较,前面"后一个元素"现变成了"前一个元素",继续跟他的"后一个元素"进行比较如果后面的元素比 他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了, 然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整 个数组中最小的数了.然后找

排序算法:选择排序

选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 平均时间复杂度:O(n2) 空间复杂度:O(1) (用于交换和记录索引) package cn.hncu; import java.sql.Timestamp; public class selectSort { public static void main(String[] args) { int[] a

Java排序算法_选择排序

选择排序的基本操作就是每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完.算法不稳定,O(1)的额外的空间,比较的时间复杂度为O(n^2),交换的时间复杂度为O(n),并不是自适应的.在大多数情况下都不推荐使用.只有在希望减少交换次数的情况下可以用. 基本思想 n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果: ①初始状态:无序区为R[1..n],有序区为空. ②第1趟排序 在无序区R[1..n]中选出关键字最小的

常见的五类排序算法图解和实现(选择类:简单选择排序,锦标赛排序,树形选择排序,堆排序)

选择类的排序算法 简单选择排序算法 采用最简单的选择方式,从头到尾扫描待排序列,找一个最小的记录(递增排序),和第一个记录交换位置,再从剩下的记录中继续反复这个过程,直到全部有序. 具体过程: 首先通过 n –1 次关键字比较,从 n 个记录中找出关键字最小的记录,将它与第一个记录交换. 再通过 n –2 次比较,从剩余的 n –1 个记录中找出关键字次小的记录,将它与第二个记录交换. 重复上述操作,共进行 n –1 趟排序后,排序结束. 如图   过程图解 令 k=i:j = i + 1: 目

经典算法:选择排序、插入排序和气泡排序的实现

将要排序的对象分作两部分,一个是一排序的,一个是未排序的,从后面未排序部分选择一个最小 值,并放入前面已排序部分的最后一个.例如: 排序前:70 80 31 37 10 1 48 60 33 80 [1] 80 31 37 10 70 48 60 33 80 选出最小值1 [1 10] 31 37 80 70 48 60 33 80 选出最小值10 [1 10 31] 37 80 70 48 60 33 80 选出最小值31 [1 10 31 33] 80 70 48 60 37 80 ....

排序高级之选择排序_选择排序

选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾.以此类推,直到所有元素均排序完毕. 选择排序的主要优点与数据移动有关.如果某个元素位于正确的最终位置上,则它不会被移动.选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换.在所有的完全依靠交换去移动元素的排序方

Javascript排序算法之合并排序的2个例子介绍

 这篇文章主要介绍了Javascript排序算法之合并排序(归并排序)的2个例子,需要的朋友可以参考下 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.   归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列.   归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(

Javascript排序算法之计数排序的实例

 计数排序是一种高效的线性排序,它通过计算一个集合中元素楚翔的次数来确定集合如何排列,计数排序不需要进行数据的比较,所有他的运行效率前面介绍的都高 计数排序(Counting sort)是一种稳定的排序算法.计数排序使用一个额外的数组Count_arr,其中第i个元素是待排序数组Arr中值等于i的元素的个数.然后根据数组Count_arr来将Arr中的元素排到正确的位置. 分为四个步骤: 1.找出待排序的数组中最大和最小的元素 2.统计数组中每个值为i的元素出现的次数,存入数组Count_arr

数据结构例程——选择排序之直接选择排序

本文是[数据结构基础系列(9):排序]中第6课时[选择排序之直接选择排序]的例程. #include <stdio.h> #define MaxSize 20 typedef int KeyType; //定义关键字类型 typedef char InfoType[10]; typedef struct //记录类型 { KeyType key; //关键字项 InfoType data; //其他数据项,类型为InfoType } RecType; //排序的记录类型定义 void Sele

Javascript排序算法之计数排序的实例_javascript技巧

计数排序(Counting sort)是一种稳定的排序算法.计数排序使用一个额外的数组Count_arr,其中第i个元素是待排序数组Arr中值等于i的元素的个数.然后根据数组Count_arr来将Arr中的元素排到正确的位置.分为四个步骤:1.找出待排序的数组中最大和最小的元素2.统计数组中每个值为i的元素出现的次数,存入数组Count_arr的第i项3.对所有的计数累加(从Count_arr中的第一个元素开始,每一项和前一项相加)4.反向遍历原数组:将每个元素i放在新数组的第Count_arr