选择排序(Selection sort)是一种不稳定的排序方法。时间复杂度O(n^2)。遍历整个数组,找到最小的与数组第一个数交换位置,第一个数有序。然后再遍历剩下待排序的数中找出最小的,与第二个位置交换,也就是已排序的末尾。 直到最后一个元素。
一. c语言版
【原版】
/* 选择排序 时间复杂度O(n^2) 不稳定的排序方法: 序列5 8 5 2 9 我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了; 思路: 遍历整个数组,找到最小的与数组第一个数交换位置,第一个数有序 然后再遍历剩下待排序的数中找出最小的,与第二个位置交换,也就是已排序的末尾。 直到最后一个元素。 */ void SelectSort1(int *arr,int len) { int i=0,j=0; int minIndex=0; for(i=0;i<len-1;i++){//因为前面都排有序了,那么最后一个也就不用循环,自然有序。 minIndex = i;//默认当前最小 for(j=i+1;j<len;j++){ if(arr[minIndex]>arr[j]){ minIndex = j;//找到最小值的下标 } } if(minIndex!=i){//如果最小值不是当前值,那么就不用交换了 swap(&arr[minIndex],&arr[i]); } } }
【优化】
/* 【选择排序优化】 思路:我们上面的每次循环的时候只是找了一个数最小值放左边,那么同时我们也可以找到最大值放右边。 例如8 4 6 2 第一次循环找到最大值 最小值的位置 maxIndex = 0 left=0 right=3 minIndex = 3 =>先交换最小值 因为左指针left正好等于maxIndex swap(&arr[minIndex],&arr[left]); 也就是 2 4 6 8 这个时候 那么这个时候0的位置 成了最小的值 改变了maxIndex 最大值跑到3的位置 所以我们做一个 maxIndex = minIndex=3; 然后再交换右边最大的数 swap(&arr[maxIndex],&arr[right]); */ void SelectSort2(int *arr,int len) { int left=0,right=0,cur=0;//左指针 右指针 当前值 int minIndex=0,maxIndex=0; for(left=0,right=len-1; left<right ; left++,right--){ minIndex = left;//最小值 下标 maxIndex = right;//最大值 下标 for(cur=left; cur<=right ; cur++){ if(arr[minIndex]>arr[cur]){ minIndex=cur; } if(arr[maxIndex]<arr[cur]){ maxIndex=cur; } } //将最小值交换到左边 swap(&arr[minIndex],&arr[left]); //因为先交换的最小值位置,但是也要考虑到最大值在最小值left的位置。 if(left == maxIndex){ maxIndex = minIndex; } swap(&arr[maxIndex],&arr[right]); } }
【完整代码】
#include<stdio.h> #include<string.h> #include<time.h> #define MAX 100000 void SelectSort1(int *arr,int len);//选择排序 每次循环找出最小值 void SelectSort2(int *arr,int len);//选择排序 优化 同时找到最大值最小值 void getRandArray(int *arr,int len,int Range); //随机生成一个长度为n一维数组 随机数的范围在[0 Range) void getNearRandArray(int *arr,int len,int times);//随机生成一个部分有序的数组 长度为n 无序交换次数 void swap(int *a,int *b); //交换两个变量 void dump(int arr[],int len); //打印 int main() { clock_t begin , end; double time; int arr1[MAX],arr2[MAX]; getRandArray(arr1,MAX,100); //getNearRandArray(arr1,MAX,5); memcpy(arr2,arr1,sizeof(arr1)); begin = clock();//开始记录 SelectSort1(arr1,MAX); end = clock(); //结束记录 time = (double)(end - begin)/CLOCKS_PER_SEC; printf("【 array length is %d 】【选择排序1】【cost time is %lf 】\n",MAX,time); begin = clock();//开始记录 SelectSort2(arr2,MAX); end = clock(); //结束记录 time = (double)(end - begin)/CLOCKS_PER_SEC; printf("【 array length is %d 】【选择排序2】【cost time is %lf 】\n",MAX,time); return 0; } /** 选择排序 时间复杂度O(n^2) 不稳定的排序方法: 序列5 8 5 2 9 我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了; 思路: 遍历整个数组,找到最小的与数组第一个数交换位置,第一个数有序 然后再遍历剩下待排序的数中找出最小的,与第二个位置交换,也就是已排序的末尾。 直到最后一个元素。 */ void SelectSort1(int *arr,int len) { int i=0,j=0; int minIndex=0; for(i=0;i<len-1;i++){//因为前面都排有序了,那么最后一个也就不用循环,自然有序。 minIndex = i;//默认当前最小 for(j=i+1;j<len;j++){ if(arr[minIndex]>arr[j]){ minIndex = j;//找到最小值的下标 } } if(minIndex!=i){//如果最小值不是当前值,那么就不用交换了 swap(&arr[minIndex],&arr[i]); } } } /* 【选择排序优化】 思路:我们上面的每次循环的时候只是找了一个数最小值放左边,那么同时我们也可以找到最大值放右边。 例如8 4 6 2 第一次循环找到最大值 最小值的位置 maxIndex = 0 left=0 right=3 minIndex = 3 =>先交换最小值 因为左指针left正好等于maxIndex swap(&arr[minIndex],&arr[left]); 也就是 2 4 6 8 这个时候 那么这个时候0的位置 成了最小的值 改变了maxIndex 最大值跑到3的位置 所以我们做一个 maxIndex = minIndex=3; 然后再交换右边最大的数 swap(&arr[maxIndex],&arr[right]); */ void SelectSort2(int *arr,int len) { int left=0,right=0,cur=0;//左指针 右指针 当前值 int minIndex=0,maxIndex=0; for(left=0,right=len-1; left<right ; left++,right--){ minIndex = left;//最小值 下标 maxIndex = right;//最大值 下标 for(cur=left; cur<=right ; cur++){ if(arr[minIndex]>arr[cur]){ minIndex=cur; } if(arr[maxIndex]<arr[cur]){ maxIndex=cur; } } //将最小值交换到左边 swap(&arr[minIndex],&arr[left]); //因为先交换的最小值位置,但是也要考虑到最大值在最小值left的位置。 if(left == maxIndex){ maxIndex = minIndex; } swap(&arr[maxIndex],&arr[right]); } } //随机生成一个数组 void getRandArray(int *arr,int len,int Range) { srand(time(NULL));//设置随机种子 int i = 0; for (i=0; i<len; i++){ arr[i] = rand() % Range;//范围在Range以内 } } //随机生成一个比较有序的数组 先有序,然后随机交换位置 void getNearRandArray(int *arr,int len,int times) { int i = 0; for(i;i<len;i++){//先构造一个有序的数组 arr[i] = i; } srand(time(NULL));//设置种子 for(i=0;i<times;i++){//尽量有序 循环交换多少次 int posx = rand()%(len-1);//在[1,len-1]上随机位置 int posy = rand()%(len-1); swap(&arr[posx],&arr[posy]);//随机交换两个位置的数 } } //交换两个值 利用指针交换位置 void swap(int *a,int *b) { int temp; temp = *a; *a = *b; *b = temp; } //打印输出数组 void dump(int *arr,int len) { int i=0; for(i=0;i<len;i++) printf("%d ",arr[i]); printf("\n");//换行 }
二. PHP版
【选择排序1】
/** 选择排序 时间复杂度 O(n^2) 不稳定性 param array $arr 要排序的数组 param int $len 数组的长度 return array $arr 排好序的数组 **/ public function selectSort1($arr,$len) { $i=$j=$minIndex=0; for($i=0;$i<$len-1;$i++){ $minIndex = $i; for($j=$i+1;$j<$len;$j++){ ($arr[$minIndex]>$arr[$j]) && ($minIndex = $j); } if($minIndex!=$i){ $this->swap($arr[$minIndex],$arr[$i]);//交换最小值 } } return $arr; }
【选择排序2】
/** * 选择排序优化 **/ public function selectSort2($arr,$len) { $left=$right=$cur=0; $minIndex=$maxIndex=0; for($left=0,$right=$len-1; $left<$right; $left++,$right--){ $minIndex = $left;//最小值的下标 $maxIndex = $right;//最大值的下表 for($cur=$left; $cur<=$right; $cur++){ ($arr[$minIndex]>$arr[$cur]) && ($minIndex=$cur); ($arr[$maxIndex]<$arr[$cur]) && ($maxIndex=$cur); } //交换最小值 $this->swap($arr[$minIndex],$arr[$left]); if($left == $maxIndex){//放置 最大值就在left的位置上。 $maxIndex = $minIndex; } $this->swap($arr[$maxIndex],$arr[$right]); } return $arr; }
【完整代码】
<?php //选择排序 class Select { const MIN = 0; const MAX = 1000;//设置随机数的范围 private $len = 10;//默认构造的数组长度 private $times= 10;//无序交换次数 public $arr = [];//要排序的数组 public $out = [];//排好序的数组 public function __construct($len=0,$times=0,$min=Select::MIN,$max=Select::MAX) { $this->len = empty($len) ? $this->len:$len;//判断要生成数组的长度 $this->times= empty($times) ? $this->times:$times; //无序交换次数 $this->arr = $this->getRandArray($this->len,$min,$max);//生成无序数组 //$this->arr = $this->getNearRandArray($this->len,$this->times,$min,$max);//生成相对有序数组 echo '数组长度:',$len,'<br/>'; echo '随机数范围:[',$min,',',$max,']','<br/>'; //echo '无序交换次数:',$times,'<br/>'; $stime=microtime(true); $this->out = $this->selectSort1($this->arr,$this->len);//调用选择排序1 $etime=microtime(true); $total=$etime-$stime; echo "<br />[选择排序]执行时间为:{$total} 秒<br/>"; $stime=microtime(true); $this->out = $this->selectSort2($this->arr,$this->len);//调用选择排序2 $etime=microtime(true); $total=$etime-$stime; echo "<br />[优化选择排序]执行时间为:{$total} 秒<br/>"; // var_dump($this->arr,$this->out); } /** 选择排序 时间复杂度 O(n^2) 不稳定性 param array $arr 要排序的数组 param int $len 数组的长度 return array $arr 排好序的数组 **/ public function selectSort1($arr,$len) { $i=$j=$minIndex=0; for($i=0;$i<$len-1;$i++){ $minIndex = $i; for($j=$i+1;$j<$len;$j++){ ($arr[$minIndex]>$arr[$j]) && ($minIndex = $j); } if($minIndex!=$i){ $this->swap($arr[$minIndex],$arr[$i]);//交换最小值 } } return $arr; } /** * 选择排序优化 **/ public function selectSort2($arr,$len) { $left=$right=$cur=0; $minIndex=$maxIndex=0; for($left=0,$right=$len-1; $left<$right; $left++,$right--){ $minIndex = $left;//最小值的下标 $maxIndex = $right;//最大值的下表 for($cur=$left; $cur<=$right; $cur++){ ($arr[$minIndex]>$arr[$cur]) && ($minIndex=$cur); ($arr[$maxIndex]<$arr[$cur]) && ($maxIndex=$cur); } //交换最小值 $this->swap($arr[$minIndex],$arr[$left]); if($left == $maxIndex){//放置 最大值就在left的位置上。 $maxIndex = $minIndex; } $this->swap($arr[$maxIndex],$arr[$right]); } return $arr; } //交换两个变量 private function swap(&$a,&$b) { $temp = 0;//借助第三个变量 $temp = $a; $a = $b; $b = $temp; } /** 生成部分有序的数组 @params $len 数组长度 @params $times 数组无序交换的次数 @params $min $max 随机数的范围 return array **/ private function getNearRandArray($len,$times,$min,$max) { $arr = [];//生成部分有序的数组 for($i=0; $i<$len; $i++){ $arr[$i] = $i; } for($i=0; $i<$times; $i++){//打乱有序 循环交换多少次 $posx = mt_rand($min,$max)%($len-1);//在[1,len-1]上随机位置 $posy = mt_rand($min,$max)%($len-1); $this->swap($arr[$posx],$arr[$posy]);//随机交换两个位置的数 } return $arr; } /** 生成随机数组 @params $len 随机数组的长度 @params $min $max 随机数的范围 **/ private function getRandArray($len,$min,$max) { $arr = [];//生成无序的数组 for($i=0; $i<$len; $i++){ $arr[$i] = mt_rand($min,$max); } return $arr; } } new Select(1000,5);//实例化类