七叶笔记 » golang编程 » 数据结构与算法-冒泡排序-插入排序-选择排序-9

数据结构与算法-冒泡排序-插入排序-选择排序-9

一、 冒泡排序

  • 冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求,如果不满足就让它俩互换。
  • 稳定性:冒泡排序是稳定的排序算法。
  • 空间复杂度:冒泡排序是原地排序算法。
  • 时间复杂度:
    (1) 最好情况(满有序度):O(n)。
    (2) 最坏情况(满逆序度):O(n^2)。

冒泡排序图解

冒泡排序降序golang语言实现图

 func bubbleSort(array []int) {
  for i := 0; i < len(array)-1; i++ {
    fmt.Printf("第%d次循环:\n", i)
    for j := i + 1; j < len(array); j++ {
      fmt.Printf("数组array第%d个元素与第%d个元素比较\n", i, j)
if array[i] > array[j] {
array[i], array[j] = array[j], array[i]
}
fmt.Printf("第%d次冒泡结果: %v \n\n", i, array)
}
}

输出:
/**
冒泡排序
old array= [4 5 6 1 3 2]
第0次循环:
数组 array 第0个元素与第1个元素比较
数组 array 第0个元素与第2个元素比较
数组 array 第0个元素与第3个元素比较
数组 array 第0个元素与第4个元素比较
数组 array 第0个元素与第5个元素比较
第0次冒泡结果: [1 5 6 4 3 2]

第1次循环:
数组 array 第1个元素与第2个元素比较
数组 array 第1个元素与第3个元素比较
数组 array 第1个元素与第4个元素比较
数组 array 第1个元素与第5个元素比较
第1次冒泡结果: [1 2 6 5 4 3]

第2次循环:
数组 array 第2个元素与第3个元素比较
数组 array 第2个元素与第4个元素比较
数组 array 第2个元素与第5个元素比较
第2次冒泡结果: [1 2 3 6 5 4]

第3次循环:
数组 array 第3个元素与第4个元素比较
数组 array 第3个元素与第5个元素比较
第3次冒泡结果: [1 2 3 4 6 5]

第4次循环:
数组 array 第4个元素与第5个元素比较
第4次冒泡结果: [1 2 3 4 5 6]

new array= [1 2 3 4 5 6]

*/  


二、插入排序

  • 插入排序将数组数据分成已排序区间和未排序区间。初始已排序区间只有一个元素,即数组第一个元素。在未排序区间取出一个元素插入到已排序区间的合适位置,直到未排序区间为空。
  • 空间复杂度:插入排序是原地排序算法。
  • 时间复杂度:
    (1) 最好情况:O(n)。
    (2) 最坏情况:O(n^2)。
    (3) 平均情况:O(n^2)(往数组中插入一个数的平均时间复杂度是O(n),一共重复n次)。
  • 稳定性:插入排序是稳定的排序算法。

插入排序图解

插入排序降序golang语言实现

 func InsertSort(array []int) {
  length := len(array)
  if length <= 1 {
return
}
for i := 1; i < length; i++ {
    //从第二个数开始,从左向右依次取数
tmp := array[i] 
    //下标从0开始,依次从左向右
j := i - 1
fmt.Printf("第%d次循环: i=%d j=%d\n", i, i, j)
//每次取到的数都跟左侧的数做比较
    //如果左侧的数比取的数大,就将左侧的数右移一位
    //直至左侧没有数字比取的数大为止
for ; j >= 0; j-- {
fmt.Printf("temp:array[%d]=%d array[%d]=%d",i,tmp,j,array[j])
if tmp < array[j] {
array[j+1] = array[j]
} else {
fmt.Println("break")
break
}
fmt.Println("数据移动", array, "j=", j, "i=", i)
}
fmt.Println("当前数组 ", array, "j=", j, "i=", i)
//将取到的数插入到不小于左侧数的位置
//array[j+1] = tmp
//数据未移动,不替换
if j+1 != i {
array[j+1] = tmp
}
fmt.Printf("第%d次循环结果%v\n\n", i, array)
}
}

输出:
/**
old array= [4 5 6 1 3 2]
第1次循环: i=1 j=0
 temp:array[1]=5 array[0]=4 break
当前数组  [4 5 6 1 3 2] j= 0 i= 1
第1次循环结果[4 5 6 1 3 2]

第2次循环: i=2 j=1
 temp:array[2]=6 array[1]=5 break
当前数组  [4 5 6 1 3 2] j= 1 i= 2
第2次循环结果[4 5 6 1 3 2]

第3次循环: i=3 j=2
 temp:array[3]=1 array[2]=6 数据移动 [4 5 6 6 3 2] j= 2 i= 3
 temp:array[3]=1 array[1]=5 数据移动 [4 5 5 6 3 2] j= 1 i= 3
 temp:array[3]=1 array[0]=4 数据移动 [4 4 5 6 3 2] j= 0 i= 3
当前数组  [4 4 5 6 3 2] j= -1 i= 3
第3次循环结果[1 4 5 6 3 2]

第4次循环: i=4 j=3
 temp:array[4]=3 array[3]=6 数据移动 [1 4 5 6 6 2] j= 3 i= 4
 temp:array[4]=3 array[2]=5 数据移动 [1 4 5 5 6 2] j= 2 i= 4
 temp:array[4]=3 array[1]=4 数据移动 [1 4 4 5 6 2] j= 1 i= 4
 temp:array[4]=3 array[0]=1 break
当前数组  [1 4 4 5 6 2] j= 0 i= 4
第4次循环结果[1 3 4 5 6 2]

第5次循环: i=5 j=4
 temp:array[5]=2 array[4]=6 数据移动 [1 3 4 5 6 6] j= 4 i= 5
 temp:array[5]=2 array[3]=5 数据移动 [1 3 4 5 5 6] j= 3 i= 5
 temp:array[5]=2 array[2]=4 数据移动 [1 3 4 4 5 6] j= 2 i= 5
 temp:array[5]=2 array[1]=3 数据移动 [1 3 3 4 5 6] j= 1 i= 5
 temp:array[5]=2 array[0]=1 break
当前数组  [1 3 3 4 5 6] j= 0 i= 5
第5次循环结果[1 2 3 4 5 6]
new array= [1 2 3 4 5 6]
*/  


三、选择排序

  • 选择排序将数组分成已排序区间和未排序区间。初始已排序区间为空。每次从未排序区间中选出最小的元素插入已排序区间的末尾,直到未排序区间为空。
  • 空间复杂度:选择排序是原地排序算法。】
  • 时间复杂度:(都是O(n^2))
    (1) 最好情况:O(n^2)。
    (2) 最坏情况:O(n^2)。
    (3) 平均情况:O(n^2)。
  • 稳定性:选择排序不是稳定的排序算法。

选择排序图解

选择排序降序golang语言实现

 func SelectSort(values []int) {
length := len(values)
if length <= 1 {
return
}
for i := 0; i < length; i++ {
    //初始的最小值位置从0开始,依次向右
min := i 
//从i右侧的所有元素中找出当前最小值所在的下标
for j := length - 1; j > i; j-- {
if values[j] < values[min] {
min = j
}
}
fmt.Printf("i:%d minIndex:%d\n", i, min)
//把每次找出来的最小值与之前的最小值做交换
values[i], values[min] = values[min], values[i]
fmt.Println(values)
}
}

输出:
/**
old array= [4 5 6 1 3 2]
i:0 minIndex:3
[1 5 6 4 3 2]
i:1 minIndex:5
[1 2 6 4 3 5]
i:2 minIndex:4
[1 2 3 4 6 5]
i:3 minIndex:3
[1 2 3 4 6 5]
i:4 minIndex:5
[1 2 3 4 5 6]
i:5 minIndex:5
[1 2 3 4 5 6]
new array= [1 2 3 4 5 6]
*/  


四、思考

  • 选择排序和插入排序的时间复杂度相同,都是O(n^2),在实际的软件开发中,为什么我们更倾向于使用插入排序而不是冒泡排序算法呢?
  • 答:从代码实现上来看,冒泡排序的数据交换要比插入排序的数据移动要复杂,冒泡排序需要3个赋值操作,而插入排序只需要1个,所以在对相同数组进行排序时,冒泡排序的运行时间理论上要长于插入排序。


下一节:

上一节:


相关文章