数据结构与算法(GO实现)-排序问题

选择排序

实现原理

选择排序(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个元素以内时),插入排序的性能可以接受,并且代码简单易懂,或者需要原地排序:插入排序是一种原地排序算法,不需要额外的存储空间。

小结

  1. 冒泡排序(Bubble Sort)
    基本思想:通过重复遍历待排序的数列,比较每对相邻元素的值,如果顺序错误就把它们交换过来。遍历数列的工作是重复进行的,直到没有再需要交换的元素为止,这时数列就排序完成了。
    时间复杂度:平均和最坏情况下为O(n^2),最好情况下(数组已经是排序状态)为O(n)。
    空间复杂度:O(1),是一种原地排序算法。
    特点:简单易懂,但效率较低,适合小规模数据或基本有序的数据集。
  2. 选择排序(Selection Sort)
    基本思想:在未排序的序列中找到最小(或最大)的元素,存放到排序序列的起始位置,然后再从剩余未排序的元素中继续寻找最小(或最大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
    时间复杂度:无论最好、最坏还是平均情况,时间复杂度均为O(n^2)。
    空间复杂度:O(1),同样是一种原地排序算法。
    特点:简单直观,但在大数据集上效率低下,不适用于大规模数据排序。
  3. 插入排序(Insertion Sort)
    基本思想:将一个记录插入到已经排序好的有序表中,从而得到一个新的、记录数增加1的有序表。即每次迭代中,从输入数据中取出一个元素,将其插入到已排序序列中的正确位置,以保持序列的有序性。
    时间复杂度:最好情况下(数组已经是排序状态)为O(n),最坏和平均情况下为O(n^2)。
    空间复杂度:O(1),也是原地排序算法。
    特点:对于小规模或部分已排序的数据集表现良好,效率较高;但在数据量大时效率降低。适合于几乎有序的数组。
    总的来说,这三种排序算法都属于简单直观的排序方法,易于理解和实现,但在处理大量数据时效率较低。在实际应用中,根据数据的具体情况和需求,可能会选择更高效的排序算法,如快速排序、归并排序等。
  • 27
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值