选择排序法
重复执行N-1次下述处理
1.找出未排序部分最小值的位置minj。
2.将minj位置的元素与未排序部分的起始元素交换。
以数组A={5,4,8,7,9,3,1}为例,我们对其使用选择排序法时,排序过程如图3.6所示。
步骤0为初始状态,此时所有元素均属于未排序部分。
在步骤1中,我们找出未排序部分最小值的位置(minj=6),然后将该位置的元素A[6](=1)与未排序部分的起始元素A[0](=5)进行交换。这样一来,已排序部分就增加了一个元素。
在步骤2中,找出未排序部分最小值的位置(minj=5),然后将该位置的元素A[5](=3)与未排序部分的起始元素A[1](=4)进行交换。后边的步骤同理,从数组开头按有小到大的顺序逐个确定每个位置的值。
实现选择排序法时需要的主要变量如图3.7所示。
A[N] 长度为N的整型数组
i 循环变量,表示未排序部分的开头元素,从数组开头向末尾移动
minj 各轮循环处理中,第i号到第N-1号元素中最小值的位置
j 循环变量,用来查找未排序部分中最小值的位置(minj)
在每一轮i的循环中,通过j自增来遍历A[i]到A[N-1],从而确定minj。确定minj后,让起始元素A[i]与最小值元素A[minj]进行交换。
考察
假设现在有一组由数字和字母组成的数据,我们试着用选择排序法对其进行升序排列。在如图3.8所示的例子里,我们"以数字为基准"进行排序,该排序数组中2个元素带有数字"3",初始状态下其顺序为3H->3D。
我们会发现,排序结束后这两个元素的顺序反了过来,变成了3D->3H。也就是说,由于选择排序法会直接交换两个不相邻的元素,所以属于不稳定的排序算法。
然后再来看看选择排序法的复杂度。假设数据总数为N,那么无论在何种情况下,选择排序法都需要进行(N-1)+(N-2)+...+1=(N^2-N)/2次比较运算,用于搜索未排序部分的最小值。因此该算法的复杂度与N^2基本成正比,即复杂度数量级为O(N^2)。
冒泡排序法与选择排序法相比,一个从局部入手减少逆序元素,一个放眼大局逐个选择最小值,二者思路大不相同。但是,它们又都有着"通过i次外层循环,从数据中顺次求出i个最小值"的相同特征。相对地,插入排序法是通过i次外层循环,直接将原数组的i个元素重新排序。另外,不含flag的简单冒泡排序法和选择排序法不依赖数据,即比较运算的次数(算法复杂度)不受输入数据影响,而插入算法在执行时却依赖数据,处理某些数据时具有很高的效率。
C语言版本:
#include<stdio.h>
int selectionSort(int A[],int N){
int i,j,t,sw=0,minj;
for(i=0;i<N-1;i++){
minj=i;
for(j=i;j<N;j++){
if(A[j]<A[minj])
minj=j;
}
t=A[i];
A[i]=A[minj];
A[minj]=t;
if(i!=minj)
sw++;
}
return sw;
}
int main(){
int A[100],N,i,sw;
scanf("%d",&N);
for(i=0;i<N;i++)
scanf("%d",&A[i]);
sw = selectionSort(A,N);
for(i=0;i<N;i++){
if(i>0)
printf(" ");
printf("%d",A[i]);
}
printf("\n");
printf("%d\n",sw);
return 0;
}
C++版本:
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
//read
int n;
cin>>n;
int a[n];
int count = 0;
for(int i=0;i<n;i++){
cin>>a[i];
}
//solve
for(int i=0;i<n;i++){
int minj = i;
for(int j=i;j<n;j++){
if(a[j]<a[minj]){
minj = j;
}
}
if(a[i]!=a[minj]){
int tmp = a[i];
a[i]=a[minj];
a[minj]=tmp;
count++;
}
}
//output
cout<<a[0];
for(int i = 1;i<n;i++){
cout<<' '<<a[i];
}
cout<<endl;
cout<<count<<endl;
}
JAVA版本:
import java.io.*;
class Main
{
public static void main(String args[])throws IOException
{
BufferedReader input=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(input.readLine());
String str=input.readLine();
String str_ary[]=str.split(" ");
int a[]=new int[n];
int x=0;
for(int i=0;i<n;i++)
{
a[i]=Integer.parseInt(str_ary[i]);
}
for(int i=0;i<n;i++)
{
int mini=i;
int lowkey=a[i];
for(int j=i;j<n;j++)
{
if(a[j]<lowkey)
{
mini=j;
lowkey=a[j];
}
}
if(a[i]>lowkey)
{
int temp=a[i];
a[i]=a[mini];
a[mini]=temp;
}
else x++;
}
for(int i=0;i<n;i++)
{
System.out.print(a[i]+((i!=n-1)?" ":"\n"));
}
System.out.println(n-x);
}
}
Python版本:
n = int(input())
*A, = map(int, input().split())
ans = 0
for i in range(n):
j = A[i:].index(min(A[i:])) + i
A[i], A[j] = A[j], A[i]
if i != j:
ans += 1
print(*A)
print(ans)
PHP版本:
<?php
$N=(int)trim(fgets(STDIN));
$A=explode(' ',trim(fgets(STDIN)));
$trade=0;
for($i=0;$i<$N;$i++){
$mini=$i;
for($j=$i;$j<$N;$j++) if($A[$j]<$A[$mini]) $mini=$j;
if($mini==$i) continue;
list($A[$i],$A[$mini])=[$A[$mini],$A[$i]];
++$trade;
}
echo implode(' ',$A),PHP_EOL,$trade;
?>
JavaScript版本:
var input = require('fs').readFileSync('/dev/stdin', 'utf8');
var lines = input.split('\n');
var n = lines[0];
var A = lines[1].split(' ').map(function(i) {
return i - 0;
});
var cnt = 0;
for (var i = 0; i < n; i++) {
var min = i;
for (var j = i; j < n; j++) {
if (A[j] < A[min])
min = j;
}
if (min == i)
continue;
var tmp = A[i];
A[i] = A[min];
A[min] = tmp;
cnt++;
}
console.log(A.join(' '));
console.log(cnt);
C#版本:
using System;
namespace Sort
{
class Progarm
{
static void Main()
{
int n = int.Parse(Console.ReadLine());
var a = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
int c = 0;
for( int i = 0; i < n; i++)
{
int m = i;
for (int j = i; j < n; j++)
if (a[j] < a[m]) m = j;
int t = a[i];
a[i] = a[m]; a[m] = t;
if (i != m) c++;
}
var r = Array.ConvertAll(a, e => e.ToString());
Console.Write("{0}\n{1}\n", string.Join(" ", r), c);
}
}
}