ALDS1_2_B:Selection Sort
選擇排序法
重複執行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);
}
}
}