选择排序算法的实现思路有点类似插入排序,也分为已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。
C++实现
#include <iostream>
#include <list>
#include <vector>
#include <map>
template<typename T>
std::ostream& print(std::ostream &out,T const &val) {
return (out << val << " ");
}
template<typename T1,typename T2>
std::ostream& print(std::ostream &out,std::pair<T1,T2> const &val) {
return (out << "{" << val.first << " " << val.second << "} ");
}
template<template<typename,typename...> class TT,typename... Args>
std::ostream& operator<<(std::ostream &out,TT<Args...> const &cont) {
for(auto&& elem : cont) print(out,elem);
out << "\n";
return out;
}
void swap(int & i, int &j){
int t = i;
i = j;
j = t;
}
void selectSort(std::vector<int> &vec){
if(vec.empty() || vec.size() == 1){
return;
}
int min ;
for(int pos = 0; pos < vec.size(); pos++){
min = pos;
for(int i = pos + 1; i < vec.size(); i++){
if(vec[min] > vec[i]){
min = i;
}
}
if(min != pos){
swap(vec[min], vec[pos]);
}
}
}
int main() {
std::vector<int> vec = {1,9,2,8,3,7,4,6,5,10, -1};
selectSort(vec);
std::cout << vec;
return 0;
}
java实现
版本1
从小到大:
1、定义一个10个int元素的数组。
2、选择第一个元素,将这个元素和剩下的九个元素相比,找出最小的那个,然后和第一个元素交换位置。如果第一个元素就是最小的元素,那么不需要交换位置(<或者>,而不是<=或者>=)
3、选择第二个元素,将这个元素和剩下的八个元素相比,找出最小的那个,然后和第二个元素交换位置。如果第二个元素就是最小的元素,那么不需要交换位置(<或者>,而不是<=或者>=)
4、。。。。。。
也可以这样想:假设第一个元素就是最小的那个元素,将这个元素和剩下的九个元素相比,看还有没有比它小的元素,如果有,就将这个元素放到最小元素的位置—第一个元素。。。。
package com.oceanstar.sort;
import java.util.Arrays;
public class sort {
public static void main(String []args){
int []arr = {199, 11, 23, 56, 55, 49, 88};
selectSort(arr);
System.out.println(Arrays.toString(arr));
}
public static int [] selectSort(int []arr){
for(int i=0; i<arr.length-1; i++){
for (int j=i+1; j<arr.length; j++){
if (arr[i]>arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
}
总结:有序区逐步扩大,无序区逐步缩小
选择排序法需要比较:9+7++6+5+4+3+2+1次
版本2
从小到大:
1、定义一个10个int元素的数组。
2、选择第一个元素为最小的元素,并用一个index和num记录下此时的值与索引。然后分别拿这个值与剩下的值相比,如果有比这个元素还要小的元素,就用index和num记录下此时的值和索引。比较完一轮之后,如果发现index不为1,那么和第一个元素相交换。
3、选择第二个元素为最小的元素,并用一个index和num记录下此时的值与索引。然后分别拿这个值与剩下的值相比,如果有比这个元素还要小的元素,就用index和num记录下此时的值和索引。比较完一轮之后,如果发现index不为2,那么和第二个元素相交换。
4、。。。
package com.oceanstar.sort;
import java.util.Arrays;
public class sort {
public static void main(String []args){
int []arr = {199, 11, 23, 56, 55, 49, 88};
selectSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[minIndex] > arr[j]) {
minIndex = j;
}
}
// 交换
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
public static void swap(int []arr, int x, int y){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
总结:比起版本1,交换的步骤要小
golang实现
int数组
package main
import (
"fmt"
"time"
)
func selectMax(arr[]int)int{
length := len(arr);
if length <= 0{
return -404;
}else if length == 1 {
return arr[0];
}else{
max := arr[0]; //假定第一个最大
for i := 1; i < length; i++{
if arr[i] > max { //任何一个比我的大的数,最大的
max = arr[i]; // 更新最大值
}
}
return max;
}
}
// // 传递引用, 因此会改变原数组的值
func SelectSortMax(arr[] int) []int {
length := len(arr);
if length <= 1 {
return arr;
}else{
for i := 0; i < length - 1 ; i++ { // 只剩下一个时不用挑选
minIndex := i; // 假定当前索引为无序区间的最小值
for j := i + 1; j < length; j++{ //向无需区间逼近
if arr[j] < arr[minIndex] {
minIndex = j;
}
}
if minIndex != i {
arr[i], arr[minIndex] = arr[minIndex], arr[i]; //数据交换
}
}
return arr;
}
}
func main() {
t := time.Now()
arr:=[]int {1,9,2,8,3,7,4,6,5,10}
fmt.Println(SelectSortMax(arr)) //[1 2 3 4 5 6 7 8 9 10]
fmt.Println(arr) //[1 2 3 4 5 6 7 8 9 10]
elapsed := time.Since(t)
fmt.Println("app elapsed:", elapsed)
}
字符串数组
- golang中的字符串排序
fmt.Println("a">"b") // f
fmt.Println("a"<"b") // t
fmt.Println("a"=="a") //t
pb:="a2"
pa:="a1"
fmt.Println("pa",&pa) //go1.1 ,1.3比较地址,go1.10 优化,比较字符串
fmt.Println("pb",&pb)
fmt.Println(pa<pb) //true
fmt.Println("a1" <"a2") //true
fmt.Println("ab" <"ac")//true
fmt.Println("a1b" <"a1c")//true
- go语言中由三种方法可以实现字符串的比较
go1.1 ,1.3比较地址,go1.10 优化,比较字符串
func main() {
fmt.Println("a" < "b") //true
pb := "b";
pa := "a";
fmt.Println(pa < pb) // true
ppa := "a";
ppb := "b";
fmt.Println(ppa < ppb) // true
//Compare 按字典顺序返回一个比较两个字符串的整数。如果 a == b,结果将为0,如果 a <b 则返回-1,如果 a> b 则返回+1。
// Compare 仅包含与封装字节的对称性。使用内置的字符串比较运算符 ==,<,> 等通常会更清晰并且速度更快。
// 先比较第一个元素,在比较第二个元素
fmt.Println(strings.Compare("123", "12")) //1
fmt.Println(strings.Compare("a1", "a12")) // -1
//自建方法“==”,区分大小写
fmt.Println("go"=="go", "GO"=="go") // true, false
fmt.Println("GO" < "go") // true
//Compare函数,区分大小写
fmt.Println(strings.Compare("GO","go")) // -1
fmt.Println(strings.Compare("go","go")) // 0
//比较UTF-8编码在小写的条件下是否相等,不区分大小写
fmt.Println(strings.EqualFold("GO","go")) // true
}
- 自己实现的选择排序: 每次选择一个目标元素,插入到指定位置,然后到剩下的位置上选择一个目标元素,插入到指定位置:
package main
import (
"fmt"
)
func SelectMaxString(arr []string) string{
length := len(arr);
if length == 0 {
return "";
}else if length == 1 {
return arr[0];
}else{
max := arr[0];
for i := 1; i < length ; i++ {
if arr[i] > max { // if strings.Compare(arr[min], arr[j]) > 0 {
max = arr[i];
}
}
return max;
}
}
// // 传递引用, 因此会改变原数组的值
func SelectSortMax(arr[] string) []string {
length := len(arr);
if length <= 1 {
return arr;
}else{
for i := 0; i < length - 1 ; i++ { // 只剩下一个时不用挑选
minIndex := i; // 假定当前索引为无序区间的最小值
for j := i + 1; j < length; j++{ //向无需区间逼近
if arr[j] < arr[minIndex] { // strings.Compare(arr[min], arr[j]) > 0
minIndex = j;
}
}
if minIndex != i {
arr[i], arr[minIndex] = arr[minIndex], arr[i]; //数据交换
}
}
return arr;
}
}
func main() {
var arr []string = []string{"aaaws", "bbb", "Aaaa", "Abab", "d", "zzz", "BAaa", "12a", "223a"}
fmt.Println(SelectSortMax(arr))
}
问题:
(1)选择排序的复杂度
选择排序的空间复杂度是O(1),是一种原地排序算法。选择排序的最好情况时间复杂度、最坏情况和平均情况时间复杂度都为 O(n )。
(2)选择排序是不是稳定的排序算法
不是,选择排序是一种不稳定的排序算法。选择排序每次都要找剩余未排序元素中的最小值,并和前面的元素交换位置,这样破坏了稳定性。
比如 5,8,5,2,9 这样一组数据,使用选择排序算法来排序的话,第一次找到最小元素2,与第一个 5 交换位置,那第一个 5 和中间的 5 顺序就变了,所以就不稳定了。正是因此,相对于冒泡排序和插入排序,选择排序就稍微逊色了。