选择排序
实现原理
选择排序(Selection Sort)是一种简单的排序算法。它的原理是从数列中选择最小(最大)的元素,将他与数列中的第一个(最后一个)元素进行交换,以此类推,直到所有元素都排序完毕
具体来说,选择排序的原理如下:
1.在数列中选择一个元素作为最小值(最大)值,将他记录下来。
2.从数列中剩余的所有元素中找出最小(最大)的元素,并与记录的最小(最大)值进行比较,如果比记录的最小(最大)值还小(大),则将他记录下来。
3.重复执行以上步骤,直到所有的元素都完成比较
4.将找到的最小(最大)值与数列中的第一个(倒数第一个)元素交换位置,继续进行下一轮排序,直到所有元素都排序完成
5.在实现时我们一般一次取最大的和最小的分别安插在区间的两端,依次往数组中间推进
代码实现
package main
import "log"
func main(){
arr := []int{99, -5, 3, 15, 51, 62, 7, 38, 19}
log.Println(arr)
selectionsort(arr)
log.Println(arr)
}
func selectionSort(arr []int){
if arr == nil || len(arr) < 2{
return
}
//长度大于等于2
n := len(arr)
//i ~ n-1范围上,找到最小值
//最小值,和i位置的数交换
for i := 0; i < n-1; i++{
//不是值,位置
minIndex := i
for j := i + 1;j < n;j++{
if arr[j] < arr[minIndex]{
minIndex = j
}
}
swap(arr,i,minIndex)
}
}
func swap(arr []int,i,j int){
tmp := arr[i]
arr[i] = arr[j]
arr[j] = tmp
}
性能分析
冒泡排序
实现原理
冒泡排序(Bubble Sort)是一种简单的排序算法。他会重复地 遍历 要排序的数列,每次遍历时将相邻的两个数进行比较,如果他们的顺序错误就进行交换,这样每一次遍历都会使数列的最后一个数到达他的最终位置,从而完成排序过程,时间复杂度为O(n^2)
详细解释 冒泡排序的原理如下:
1.从数列的第一个元素开始,依次比较每一对相邻的元素,如果他们的顺序错误就进行交换,把较大的数交换到后面,较小的数交换到前面
2.对整个数列进行一次遍历后,则数列中最大的数就会移到最后面的位置。
3.重复以上操作,每次遍历数列的元素个数减一,直到遍历完所有元素为止
代码实现
package main
import "log"
func main(){
arr := []int{10,3,-9,-8,11,99,22}
log.Println(arr)
bubblesort(arr)
log.Println(arr)
}
func bubbleSort(arr []int){
if arr == nil || len(arr) <= 2{
return
}
n := len(arr)
for end := n-1; end > 0; end--{
for i := 0; i < end; i++{
if arr[i] > arr[end-1]{
swap(arr,i,end)
}
}
}
}
func swap(arr []int,i , j int){
temp := arr[i]
arr[i] = arr[j] arr[j] = temp
}
性能分析
在平均情况下,冒泡排序的时间复杂度也是O(n^2),因为每趟遍历中平均需要比较和交换n/2次。考虑到冒泡排序的时间复杂度较高,对于大规模的数据排序是不推荐使用的。当待排序数组的大小较小(例如100个元素以内)时,冒泡排序的性能可以接受,并且代码简单易懂。
插入排序
实现原理
插入排序(Insertion Sort)的原理是将数列分成已排序部分和未排序部分,每次从未排序的部分中取出一个数,然后插入到已排序部分的合适位置直到所有数都插入完成。这个过程类似于打扑克牌时将手里的牌排序,时间复杂的为O(n^ 2),在非纯逆序的情况下,时间复杂的一般为O(n)和O(n^2)之间.
具体来说,插入排序的原理如下
1.将数列的第一个元素看作已排序部分,将后面的所有元素看作未排序部分。
2.每次从未排序部分中取出一个元素,然后将它插入到已排序部分的合适位置中,使得插入后的数列依旧有序
3.重复执行以上步骤,直到所有元素都插入完成。
代码实现
package main
import "log"
func main(){
arr := []int{-99, 9, 8, 55, 12, -8, -11, 2}
log.Println(arr)
insertSort(arr)
log.Println(arr)
}
func insertSort(arr []int){
if arr == nil || len(arr) < 2{
return
}
n := len(arr)
for i := 1; i < n; i++ {
for j := i - 1; j >= 0 && arr[j] > arr[j+1]
swap(arr,j,j+1)
}
}
func swap(arr []int,i,j int){
tmp := arr[i]
arr[i] = arr[j]
arr[j] = tmp
}
性能分析
在平均情况下,插入排序的时间复杂度也是O(n^2)。
部分有序数组:当待排序数组在某种程度上已经部分有序时,插入排序的性能较好。
数据量较小:当待排序的数组大小较小(例如100个元素以内时),插入排序的性能可以接受,并且代码简单易懂,或者需要原地排序:插入排序是一种原地排序算法,不需要额外的存储空间。
小结
- 冒泡排序(Bubble Sort)
基本思想:通过重复遍历待排序的数列,比较每对相邻元素的值,如果顺序错误就把它们交换过来。遍历数列的工作是重复进行的,直到没有再需要交换的元素为止,这时数列就排序完成了。
时间复杂度:平均和最坏情况下为O(n^2),最好情况下(数组已经是排序状态)为O(n)。
空间复杂度:O(1),是一种原地排序算法。
特点:简单易懂,但效率较低,适合小规模数据或基本有序的数据集。 - 选择排序(Selection Sort)
基本思想:在未排序的序列中找到最小(或最大)的元素,存放到排序序列的起始位置,然后再从剩余未排序的元素中继续寻找最小(或最大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
时间复杂度:无论最好、最坏还是平均情况,时间复杂度均为O(n^2)。
空间复杂度:O(1),同样是一种原地排序算法。
特点:简单直观,但在大数据集上效率低下,不适用于大规模数据排序。 - 插入排序(Insertion Sort)
基本思想:将一个记录插入到已经排序好的有序表中,从而得到一个新的、记录数增加1的有序表。即每次迭代中,从输入数据中取出一个元素,将其插入到已排序序列中的正确位置,以保持序列的有序性。
时间复杂度:最好情况下(数组已经是排序状态)为O(n),最坏和平均情况下为O(n^2)。
空间复杂度:O(1),也是原地排序算法。
特点:对于小规模或部分已排序的数据集表现良好,效率较高;但在数据量大时效率降低。适合于几乎有序的数组。
总的来说,这三种排序算法都属于简单直观的排序方法,易于理解和实现,但在处理大量数据时效率较低。在实际应用中,根据数据的具体情况和需求,可能会选择更高效的排序算法,如快速排序、归并排序等。