首要弄清楚有哪十种:
然后下文尽量运用简略言语来协助理解,并运用Go言语来完结。 下面给定的数组都默认为[9,2,5,7,3,1,8,1,3,9]含十个元素的数组
1.冒泡排序
冒泡排序应该是大多数人接触的第一种排序算法。 其是一种简略的排序算法,其根本思维是经过重复地交流相邻的元素来将待排序的元素依照次序逐渐“冒泡”到正确的方位。
就按从小到大进行排序
具体进程如下:
- 从待排序的列表的第一个元素开端,顺次比较相邻的两个元素的巨细。
- 假如前一个元素大于后一个元素,就交流这两个元素的方位,将较大的元素向后移动。
- 持续对列表中的每一对相邻元素进行比较和交流操作,直到终究一个元素。 重复上述进程,每次都将待排序的元素“冒泡”到正确的方位,直到整个列表排序完结。
界说数组arr := []int{9, 2, 5, 7, 3, 1, 8, 1, 3, 9}
只完结函数部分
func maopao(arr []int) {
//应该传入参数--数组.回来的参数也是数组
for i := 0; i < len(arr)-1; i {
for j := i 1; j < len(arr); j {
if arr[i] > arr[j] {
arr[i],arr[j] = arr[j],arr[i]
}
}
}
}
2. 挑选排序
挑选排序是一种简略直观的排序算法,其根本思维是每次从待排序的元素中挑选最小(或最大)的元素,并将其放置在已排序部分的结尾。
具体进程如下:
- 首要,在待排序的列表中找到最小(或最大)的元素,记为最小元素。
- 将最小元素与列表的第一个元素进行交流,将最小元素放置在已排序部分的结尾。
- 接下来,在剩下的未排序部分中找到最小(或最大)的元素,再次进行交流,将它放置在已排序部分的结尾。
重复上述进程,每次从剩下的未排序部分中挑选最小(或最大)的元素,并将其放置在已排序部分的结尾,直到整个列表排序完结。
挑选排序的中心思维是不断地挑选最小(或最大)的元素,逐渐构建有序序列。
func xuanze(arr []int) {
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
}
}
arr[i], arr[min] = arr[min], arr[i]
}
}
个人感觉写下来比冒泡排序好在,他是把整个数组中的最小值给遍历出来今后,在进行方位的改换。不需求像冒泡排序那样频繁的进行交流。
但是在稳定性方面,挑选排序是不稳定的排序算法,即相同元素的相对方位可能会发生变化。而冒泡排序是稳定的排序算法,相同元素的相对方位不会改动。假如需求坚持相同元素的相对次序,冒泡排序可能更适合。
3.刺进排序
刺进排序是一种简略直观的排序算法,其根本思维是将待排序元素顺次刺进到已排序序列中的适宜方位,终究得到一个有序序列。
具体进程如下:
- 将待排序元素分红已排序部分和未排序部分。
- 从未排序部分顺次取出一个元素,将它刺进到已排序部分的适宜方位,使已排序部分仍然坚持有序。
- 重复第二步,直到未排序部分为空,一切元素都被刺进到已排序部分中。
刺进排序的中心思维是:将每个元素刺进到已排序序列中的适宜方位,逐渐构建有序序列。在履行进程中,刺进排序能够经过比较和移动元素方位来完结刺进操作。
刺进排序的时刻复杂度为O(n^2),其中n是待排序列表的长度。在实际应用中,关于小规模数据的排序任务,刺进排序的功能一般比较高效,由于它只需求常数级的额外空间,而且关于简直有序的列表,刺进排序的表现十分超卓。
func charu(arr []int) {
for i := 1; i < len(arr); i {
tmp := arr[i]
j := i - 1
//将比tmp大的往右移动
for j >= 0 && arr[j] > tmp {
arr[j 1] = arr[j]
j = j - 1
}
arr[j 1] = tmp //将tmp刺进正确的方位
}
}
大概思路便是,先把初始的i设为1,然后对i之前的数进行比较挑选其适宜巨细的地方刺进。i进行累加。时刻复杂度还是挺高的是n^2
4.希尔排序
希尔排序(Shell Sort)是刺进排序的一种改善版别,也被称为“缩小增量排序”。它的主要思维是经过比较间隔较远的元素,逐渐减小这个间隔,然后使得数组中的元素能够更快地挨近它们终究的排序方位。
希尔排序的根本进程如下:
- 挑选一个增量序列,一般为 n/2,n/4,n/8,… 直到增量为1。
- 对每个增量,运用刺进排序对子数组进行排序。
- 逐渐减小增量,重复进程2,直到增量为1。
希尔排序的要害在于挑选恰当的增量序列,不同的增量序列可能导致不同的功能。
希尔排序是依据刺进排序的以下两点性质而提出改善方法的:
- 刺进算法在对简直现已排好序的数据操作时,效率高,即可达线性排序效率
- 但刺进排序一般来说是低效的,由于每次只能将数据移动一位
一句话总结便是:两个两个换方位,将整个序列变成根本排好序的(能够有效改动刺进排序只能一个一个更改方位的问题)
func xier(arr []int) {
//挑选增量序列
for gap := len(arr) / 2; gap > 0; gap /= 2 {
for i := gap; i < len(arr); i {
tmp := arr[i]
j := i
//将比tmp大的往右移动
for j >= gap && arr[j-gap] > tmp {
arr[j] = arr[j-gap]
j = j - gap
}
arr[j] = tmp //将tmp刺进正确的方位
}
}
}
5.归并排序
归并排序是一种经典的排序算法,它采用分治的思维来进行排序。它的根本思维是将待排序的序列不断地拆分红较小的子序列,直到每个子序列只有一个元素,然后再将这些子序列两两兼并并排序,终究得到彻底排序的序列。
归并排序的完结进程如下:
- 将待排序的序列不断拆分红两个较小的子序列,直到每个子序列只有一个元素。
- 逐层兼并相邻的子序列,并依照从小到大的次序进行排序。兼并时需求额外的辅助空间来存储兼并后的成果。
- 重复进程2,直到一切的子序列兼并成一个完整的有序序列。
func guibing(arr []int) []int {
if len(arr) <= 1 {
return arr
}
mid := len(arr) / 2
left := guibing(arr[:mid])
right := guibing(arr[mid:])
return merge(left, right)
}
func merge(left, right []int) []int {
result := make([]int, 0)
i, j := 0, 0
for i < len(left) && j < len(right) {
if left[i] < right[j] {
result = append(result, left[i])
i
} else {
result = append(result, right[j])
j
}
}
result = append(result, left[i:]...)
result = append(result, right[j:]...)
return result
}
result = append(result, left[i:]...)
是 Go 言语中的切片操作语法。它的作用是将切片 left[i:] 中的一切元素追加到切片 result 的结尾。
在归并排序的 merge 函数中,咱们运用这个语法来将剩下未兼并的元素直接添加到成果切片中。left[i:] 表明从索引 i 开端到切片结尾的一切元素,… 表明将切片展开成单个元素。经过将这些元素追加到 result 切片中,咱们能够坚持兼并后的序列的有序性。
例如,假定 left 切片为 [1, 3, 5],right 切片为 [2, 4, 6],在兼并进程中,当比较完 [1, 3, 5] 和 [2, 4, 6] 的元素后,left 中还剩下一个元素 5。为了确保有序性,咱们需求将 5 追加到 result 中,这就能够经过 result = append(result, left[i:]…) 完结。运用俩个append是由于不确认左右两边最大的值在哪。
这种切片操作语法能够方便地处理切片之间的拼接和追加操作,使代码更加简洁和易读。
6.快速排序
快速排序的要害在于分区操作,经过不断地将元素移到基准值的左右两边,终究能够将序列分割成若干个子序列,使得基准值左面的元素都小于基准值,右边的元素都大于基准值。这样,在递归排序时,就能够确保基准值的方位是正确的,终究得到彻底有序的序列。
快速排序是一种常用的排序算法,其能够总结为以下几步:
-
挑选一个基准值(pivot):从待排序序列中挑选一个元素作为基准值。一般设第一个的多
-
分区(Partition):将序列中比基准值小的元素放到基准值的左面,比基准值大的元素放到右边。经过这一步操作之后,基准值将位于终究排序序列的正确方位。
-
递归排序:对基准值左右两边的子序列别离重复上述进程,直到每个子序列只剩下一个元素停止。
-
兼并成果:将一切子序列的成果兼并起来,即得到终究排好序的序列。
func kuaipai(arr []int, left, right int) int { //先完结分区
private := arr[left] //先选第一个为特定元素
//然后分红俩部分,一部分大一部分小
for left < right {
for left < right && arr[right] <= private {
right--
}
arr[left] = arr[right]
for left < right && arr[left] < private {
left
}
arr[right] = arr[left]
}
arr[left] = private
return left
}
func Quick(arr []int, left, right int) {
if left < right {
private := sort(arr, left, right)
Quick(arr, left, private-1)
Quick(arr, private 1, right)
}
}
7.堆排序
堆排序是一种依据二叉堆数据结构的排序算法,其根本思维能够总结为以下几步:
-
构建最大堆(Max Heap):将待排序序列构建成一个最大堆,即满意父节点的值大于等于其子节点的值。
-
堆排序:不断地将堆顶元素(最大值)与堆的终究一个元素交流,并对剩下元素重新进行最大堆调整。这样,每次交流后,最大值就会被放置在正确的方位上。
-
重复履行进程2,直到一切元素都被排序结束。
代码完结如下
// 调整堆,将以rootIndex为根节点的子树调整为最大堆
func maxHeapify(arr []int, n int, rootIndex int) {
largest := rootIndex // 假定根节点最大
left := 2*rootIndex 1 // 左子节点
right := 2*rootIndex 2 // 右子节点
// 找出左右子节点和根节点中的最大值
if left < n && arr[left] > arr[largest] {
largest = left
}
if right < n && arr[right] > arr[largest] {
largest = right
}
// 假如最大值不是根节点,则交流根节点和最大值,并持续调整子树
if largest != rootIndex {
arr[rootIndex], arr[largest] = arr[largest], arr[rootIndex]
maxHeapify(arr, n, largest)
}
}
// 堆排序
func dui(arr []int) {
n := len(arr)
// 构建最大堆
for i := n/2 - 1; i >= 0; i-- {
maxHeapify(arr, n, i)
}
// 交流堆顶元素和终究一个元素,然后重新调整堆
for i := n - 1; i > 0; i-- {
arr[0], arr[i] = arr[i], arr[0]
maxHeapify(arr, i, 0)
}
}
8.计数排序
计数排序是一种非比较性的排序算法,适用于待排序元素的取值规模比较小的情况。其根本思维能够概括如下:
- 找出待排序序列中的最大值,以确认计数数组的长度。
- 遍历待排序序列,计算每个元素呈现的次数,将计算成果存储在计数数组中。
- 依据计数数组中的计算信息,重新生成有序的序列。
func jishu(arr []int, maxValue int) []int {
n := len(arr)
output := make([]int, n)
// 初始化计数数组并计算每个元素呈现的次数
count := make([]int, maxValue 1)
for i := 0; i < n; i {
count[arr[i]]
}
// 对计数数组进行累加,得到每个元素在排序后的序列中的方位
for i := 1; i <= maxValue; i {
count[i] = count[i-1]
}
// 依据计数数组的信息,将元素放置到输出数组中
for i := n - 1; i >= 0; i-- {
output[count[arr[i]]-1] = arr[i]
count[arr[i]]--
}
return output
}
func getMax(arr []int) (max int) {
max = arr[0]
for _, v := range arr {
if max < v {
max = v
}
}
return
}
8.桶排序
桶排序是一种分布式排序算法,它将待排序的元素分到不同的桶中,每个桶别离进行排序,然后将桶中的元素按次序兼并得到终究的有序序列。桶排序的根本思维如下:
- 确认桶的数量和规模,将待排序的元素均匀地分到这些桶中。
- 对每个桶中的元素进行排序,能够运用其他排序算法如刺进排序、快速排序等。
- 将各个桶中的元素按次序顺次兼并,得到终究的有序序列。
func tong(arr []int) {
n := len(arr)
if n <= 1 {
return
}
// 找到最大值
maxVal := arr[0]
for i := 1; i < n; i {
if arr[i] > maxVal {
maxVal = arr[i]
}
}
// 确认桶的数量
numOfBuckets := maxVal 1
buckets := make([][]int, numOfBuckets)
// 将元素分配到桶中
for i := 0; i < n; i {
index := arr[i]
buckets[index] = append(buckets[index], arr[i])
}
// 兼并桶中的元素
index := 0
for i := 0; i < numOfBuckets; i {
for j := 0; j < len(buckets[i]); j {
arr[index] = buckets[i][j]
index
}
}
}
10.基数排序
基数排序是一种非比较型整数排序算法,它的根本思维是将待排序的整数依照位数进行分化,然后顺次对每一位进行桶排序。这个进程需求运用多轮桶排序,从最低位到最高位,直到一切位都排好序。
func radixSort(arr []int) {
n := len(arr)
if n <= 1 {
return
}
// 获取最大值
max := arr[0]
for _, val := range arr {
if val > max {
max = val
}
}
// 对每一位进行计数排序
for exp := 1; max/exp > 0; exp *= 10 {
output := make([]int, n)
count := [10]int{}
// 计算每个数字呈现的次数
for i := 0; i < n; i {
count[(arr[i]/exp)%10]
}
// 将count[i]更新为包括小于等于i的元素个数
for i := 1; i < 10; i {
count[i] = count[i-1]
}
// 依据count数组将元素放到输出数组中
for i := n - 1; i >= 0; i-- {
output[count[(arr[i]/exp)%10]-1] = arr[i]
count[(arr[i]/exp)%10]--
}
// 将输出数组复制到原始数组
for i := 0; i < n; i {
arr[i] = output[i]
}
}
}