非完全原创,部分内容来自于学习其他人的理论和B站视频。如果有侵权,请联系我,可以立即删除掉。
所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。
T(n)
,定义为任何大小的输入n
所需的最大运行时间。如果T(n)
的上界与输入大小无关,则称其具有常数时间,记作O(1)
时间;若T(n) = O( (logn)^k )
,则称其具有对数时间;若T(n) = O(k*n) = O(n)
,则称其具有线性时间;若T(n) = O(M^n)
和M = O(T(n))
, 则称其具有指数时间;若T(n) = O(n^k)
,则称其具有k次方时间。主要分为:冒泡排序,选择排序,插入排序,希尔排序,归并排序,快速排序,基数排序,堆排序,计数排序,桶排序
上述排序过程,固定需要对数组遍历(n-1)次,所耗费的时间较多。
如果在数组中的某一次遍历时,遍历的数组范围就已经有序了,那就说明整个数组已经是有序的,无需继续进行遍历。
按照这个思路,可以进行以下操作:
(1)在数组的每一趟遍历开始时设置一个标志位,初始值为true
,假定当前数组是有序的
(2)在数组中元素两两比较中,如果发生了数据交换,则代表不是有序,将标志位设为false
;如果没发生交换,则代表当前比较的数据范围是有序的,而剩余的数据则是已排好序的,因此整个数组此时已经是有序的
(3)当前遍历完成之后,根据标志位判断当前数组是否有序,有序则退出遍历
注意:该方法可能可以减少比较的趟数
分析:假如冒泡排序按照 将较大的元素往后调 的思路
(1)第m
趟排序后当前数组正好后面的数据都已排好序(假设是[k+1, n],k < n-m),则按照上一个方法,第m+1
趟排序的数组范围是[0, n-m]
(2)如果设置一个索引记录上一次最后发生交换的元素索引k
,则第m+1
趟排序的数组范围是[0, k]
,则该范围比[0, n-m]
更小,因而可以减少第二层循环的次数,从而减少程序的运行时间
BubblePlus
需要比较5*(9+5)/2 = 35
次;BubbleOrdered
需要比较9+3+2+1 = 15
次BubbleOrdered
排序的说明:[2 1 4 3 0 5 6 7 8 9]
--> [1 2 4 3 0 5 6 7 8 9]
--> [1 2 3 4 0 5 6 7 8 9]
--> [1 2 3 (0) 4 5 6 7 8 9]
。注意:由于arr[j]
与arr[j+1]
进行比较,因此0
对应的索引3
就是第一趟确定的k
值[0, 3]
,但是由于但是由于数据是两两比较的,因此,4个数据需要比较3次。其他趟依此类推。package main
import "fmt"
const size = 10
func Bubble(arr *[size]int) {
var i, j int //用于两层循环
cnt := 0 //记录循环/元素比较的次数
swap_cnt := 0 //记录发生交换的次数
fmt.Println("原数组序列: ", *arr)
for i = 0; i < len(arr)-1; i++ {
/*
//每次都将较小的元素往前移
for j = len(arr) - 1; j > i; j-- {
if arr[j] < arr[j-1] {
arr[j], arr[j-1] = arr[j-1], arr[j]
flag = false
}
}
*/
//每次都将较大的元素往后移
for j = 0; j < len(arr)-i-1; j++ {
if arr[j] > arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
swap_cnt++
}
}
fmt.Printf("第[%02d]趟: %v\n", i+1, *arr)
cnt += j
}
fmt.Printf("【Bubble】排序的趟数: %d, 排序元素比较的次数: %d, 发生元素交换的次数: %d\n", i, cnt, swap_cnt)
}
func BubblePlus(arr *[size]int) {
var i, j int //用于两层循环
var flag bool //设置标志位
cnt := 0 //记录循环/元素比较的次数
swap_cnt := 0 //记录发生交换的次数
fmt.Println("原数组序列: ", *arr)
for i = 0; i < len(arr)-1; i++ {
flag = true //假设当前数组是有序的
//每次都将较大的元素往后移
for j = 0; j < len(arr)-i-1; j++ {
if arr[j] > arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
swap_cnt++
flag = false //有元素交换,则表示当前数组无序
}
}
fmt.Printf("第[%02d]趟: %v\n", i+1, *arr)
cnt += j
if flag {
break
}
}
fmt.Printf("【BubblePlus】排序的趟数: %d, 排序元素比较的次数: %d, 发生元素交换的次数: %d\n", i+1, cnt, swap_cnt)
}
func BubbleOrdered(arr *[size]int) {
var i, j int //用于两层循环
var flag bool //设置标志位
var index int = len(arr) - 1 //记录上一趟排序中最后发生交换的索引
var tmp int //中间变量,记录每一次发生交换时的索引
cnt := 0 //记录循环/元素比较的次数
swap_cnt := 0 //记录发生交换的次数
fmt.Println("原数组序列: ", *arr)
for i = 0; i < len(arr)-1; i++ {
flag = true //假设当前数组是有序的
//每次都将较大的元素往后移
for j = 0; j < index; j++ {
if arr[j] > arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
swap_cnt++
flag = false //有元素交换,则表示当前数组无序
tmp = j
}
}
index = tmp
fmt.Printf("第[%02d]趟: %v\n", i+1, *arr)
cnt += j
if flag {
break
}
}
fmt.Printf("【BubbleOrdered】排序的趟数: %d, 排序元素比较的次数: %d, 发生元素交换的次数: %d\n", i+1, cnt, swap_cnt)
}
func main() {
arr := [size]int{5, 0, 4, 3, 9, 1, 7, 8, 2, 6}
var arr_tmp [size]int = arr
Bubble(&arr_tmp)
arr_tmp = arr
BubblePlus(&arr_tmp)
fmt.Printf("\n\n")
arr = [size]int{2, 1, 4, 3, 0, 5, 6, 7, 8, 9}
arr_tmp = arr
BubblePlus(&arr_tmp)
arr_tmp = arr
BubbleOrdered(&arr_tmp)
}
原数组序列: [5 0 4 3 9 1 7 8 2 6]
第[01]趟: [0 4 3 5 1 7 8 2 6 9]
第[02]趟: [0 3 4 1 5 7 2 6 8 9]
第[03]趟: [0 3 1 4 5 2 6 7 8 9]
第[04]趟: [0 1 3 4 2 5 6 7 8 9]
第[05]趟: [0 1 3 2 4 5 6 7 8 9]
第[06]趟: [0 1 2 3 4 5 6 7 8 9]
第[07]趟: [0 1 2 3 4 5 6 7 8 9]
第[08]趟: [0 1 2 3 4 5 6 7 8 9]
第[09]趟: [0 1 2 3 4 5 6 7 8 9]
【Bubble】排序的趟数: 9, 排序元素比较的次数: 45, 发生元素交换的次数: 19
原数组序列: [5 0 4 3 9 1 7 8 2 6]
第[01]趟: [0 4 3 5 1 7 8 2 6 9]
第[02]趟: [0 3 4 1 5 7 2 6 8 9]
第[03]趟: [0 3 1 4 5 2 6 7 8 9]
第[04]趟: [0 1 3 4 2 5 6 7 8 9]
第[05]趟: [0 1 3 2 4 5 6 7 8 9]
第[06]趟: [0 1 2 3 4 5 6 7 8 9]
第[07]趟: [0 1 2 3 4 5 6 7 8 9]
【BubblePlus】排序的趟数: 7, 排序元素比较的次数: 42, 发生元素交换的次数: 19
原数组序列: [2 1 4 3 0 5 6 7 8 9]
第[01]趟: [1 2 3 0 4 5 6 7 8 9]
第[02]趟: [1 2 0 3 4 5 6 7 8 9]
第[03]趟: [1 0 2 3 4 5 6 7 8 9]
第[04]趟: [0 1 2 3 4 5 6 7 8 9]
第[05]趟: [0 1 2 3 4 5 6 7 8 9]
【BubblePlus】排序的趟数: 5, 排序元素比较的次数: 35, 发生元素交换的次数: 6
原数组序列: [2 1 4 3 0 5 6 7 8 9]
第[01]趟: [1 2 3 0 4 5 6 7 8 9]
第[02]趟: [1 2 0 3 4 5 6 7 8 9]
第[03]趟: [1 0 2 3 4 5 6 7 8 9]
第[04]趟: [0 1 2 3 4 5 6 7 8 9]
第[05]趟: [0 1 2 3 4 5 6 7 8 9]
【BubbleOrdered】排序的趟数: 5, 排序元素比较的次数: 15, 发生元素交换的次数: 6
n
个元素,将最小的元素与第一个元素进行交换n-1
个元素,将最小的元素与第二个元素进行交换主要的思想,就是直接让每一趟确认两个位置的元素:
前面的方法,排序的总趟数是固定的:假设数组长度为N
,原始简单排序的趟数是n-1
,改进思路1的趟数是n/2
但是,如果选择排序中,中间某一次排完序之后,剩下来的元素已经是有序的,那么通过前面的方法,多余的趟数显得没有必要。
由于剩下来的元素是有序的(设其长度为k
),因此可以假设最小元素的下标是最后一个元素,从后往前扫描并与最小元素比较,那么最小元素的下标将随着扫描不断往前移动,即移动的次数=剩余数组中有序元素个数=k
,此时移动的次数与当前趟数之和就等于数组的长度-1
,于是可以跳出循环
package main
import "fmt"
const size = 10
func Select(arr *[size]int) {
var i, j int //用于两层循环
var min int //记录最小元素的索引
cnt := 0 //记录循环/元素比较的次数
swap_cnt := 0 //记录发生交换的次数
fmt.Println("原数组序列: ", *arr)
for i = 0; i < len(arr)-1; i++ {
min = i
//查找更小的元素
for j = i + 1; j < len(arr); j++ {
if arr[j] < arr[min] {
min = j
}
}
if min != i {
arr[i], arr[min] = arr[min], arr[i]
swap_cnt++
}
fmt.Printf("第[%02d]趟: %v\n", i+1, *arr)
cnt += j
}
fmt.Printf("【Select】排序的趟数: %d, 排序元素比较的次数: %d, 发生元素交换的次数: %d\n", i, cnt, swap_cnt)
}
func SelectTwo(arr *[size]int) {
var i, j int //用于两层循环
var min, max int //记录最小元素的索引
var max_bound int //记录查找范围的最大值
cnt := 0 //记录循环/元素比较的次数
swap_cnt := 0 //记录发生交换的次数
fmt.Println("原数组序列: ", *arr)
for i = 0; i < len(arr)/2; i++ {
min = i
max_bound = len(arr) - i - 1
max = max_bound
//查找更小的元素
for j = i; j <= max_bound; j++ {
if arr[j] < arr[min] {
min = j
}
if arr[j] > arr[max] {
max = j
}
}
if min != i {
arr[i], arr[min] = arr[min], arr[i]
swap_cnt++
}
//注意:此处很重要!!!
if max == i { //如果最大值刚好在第i个位置
max = min //因为min和i已经换位了,所以max应该重新指到min
}
if max != max_bound {
arr[max_bound], arr[max] = arr[max], arr[max_bound]
swap_cnt++
}
fmt.Printf("第[%02d]趟: %v\n", i+1, *arr)
cnt += j - i
}
fmt.Printf("【SelectTwo】排序的趟数: %d, 排序元素比较的次数: %d, 发生元素交换的次数: %d\n", i, cnt, swap_cnt)
}
func SelectLogOrder(arr *[size]int) {
var i, j int //用于两层循环
var min int //记录最小元素的索引
var order_cnt int //从后往前查找,记录后面有序元素的个数
cnt := 0 //记录循环/元素比较的次数
swap_cnt := 0 //记录发生交换的次数
fmt.Println("原数组序列: ", *arr)
for i = 0; i < len(arr)-1; i++ {
min = len(arr) - 1
order_cnt = 0
//查找更小的元素
for j = len(arr) - 2; j >= i; j-- {
if arr[min] > arr[j] {
min = j
order_cnt++
}
}
cnt += len(arr) - 2 - j
if min != i {
arr[i], arr[min] = arr[min], arr[i]
swap_cnt++
}
fmt.Printf("第[%02d]趟: %v\n", i+1, *arr)
//如果后面元素完全有序,前面元素也是有序,则可以跳出循环
if order_cnt+i == len(arr)-1 {
break
}
}
fmt.Printf("【SelectLogOrder】排序的趟数: %d, 排序元素比较的次数: %d, 发生元素交换的次数: %d\n", i+1, cnt, swap_cnt)
}
func main() {
arr := [size]int{8, 0, 4, 3, 1, 7, 6, 5, 2, 9}
var arr_tmp [size]int = arr
Select(&arr_tmp)
arr_tmp = arr
SelectTwo(&arr_tmp)
arr_tmp = arr
SelectLogOrder(&arr_tmp)
}
原数组序列: [8 0 4 3 1 7 6 5 2 9]
第[01]趟: [0 8 4 3 1 7 6 5 2 9]
第[02]趟: [0 1 4 3 8 7 6 5 2 9]
第[03]趟: [0 1 2 3 8 7 6 5 4 9]
第[04]趟: [0 1 2 3 8 7 6 5 4 9]
第[05]趟: [0 1 2 3 4 7 6 5 8 9]
第[06]趟: [0 1 2 3 4 5 6 7 8 9]
第[07]趟: [0 1 2 3 4 5 6 7 8 9]
第[08]趟: [0 1 2 3 4 5 6 7 8 9]
第[09]趟: [0 1 2 3 4 5 6 7 8 9]
【Select】排序的趟数: 9, 排序元素比较的次数: 90, 发生元素交换的次数: 5
原数组序列: [8 0 4 3 1 7 6 5 2 9]
第[01]趟: [0 8 4 3 1 7 6 5 2 9]
第[02]趟: [0 1 4 3 2 7 6 5 8 9]
第[03]趟: [0 1 2 3 4 5 6 7 8 9]
第[04]趟: [0 1 2 3 4 5 6 7 8 9]
第[05]趟: [0 1 2 3 4 5 6 7 8 9]
【SelectTwo】排序的趟数: 5, 排序元素比较的次数: 30, 发生元素交换的次数: 5
原数组序列: [8 0 4 3 1 7 6 5 2 9]
第[01]趟: [0 8 4 3 1 7 6 5 2 9]
第[02]趟: [0 1 4 3 8 7 6 5 2 9]
第[03]趟: [0 1 2 3 8 7 6 5 4 9]
第[04]趟: [0 1 2 3 8 7 6 5 4 9]
第[05]趟: [0 1 2 3 4 7 6 5 8 9]
第[06]趟: [0 1 2 3 4 5 6 7 8 9]
第[07]趟: [0 1 2 3 4 5 6 7 8 9]
【SelectLogOrder】排序的趟数: 7, 排序元素比较的次数: 42, 发生元素交换的次数: 5