基础算法 - 常用排序

以下是使用Go语言实现的六种排序算法以及对它们的优劣分析。这里采用了泛型的写法,这样可以支持多种类型的排序,比如整数、浮点数、字符串等。

1. 冒泡排序

冒泡排序是一种比较简单的排序算法,其基本思想是将相邻的元素两两比较,将较大的元素向后移动,直到没有相邻元素可以比较,再重新从头开始直到排序完成。冒泡排序的时间复杂度为 O(n^2),空间复杂度为 O(1)。冒泡排序的优点是代码简单易懂,缺点是效率低下,对于大规模数据排序不适用。

func BubbleSort(data []interface{}, less func(a, b interface{}) bool) {
    n := len(data)
    for i := 0; i < n-1; i++ {
        for j := 0; j < n-1-i; j++ {
            if less(data[j+1], data[j]) {
                data[j], data[j+1] = data[j+1], data[j]
            }
        }
    }
}

2. 插入排序

插入排序的基本思想是将待排序的元素插入到已经排序好的序列中,初始时假设第一个元素已经排好序,接着将第二个元素插入到第一个元素前或后,使得前两个元素有序。然后将第三个元素插入到前两个元素中,使得前三个元素有序。以此类推,直到最后一个元素插入到有序序列中,整个序列就排好序了。插入排序的时间复杂度为 O(n^2),空间复杂度为 O(1)。插入排序的优点是对于小规模数据排序非常高效,且可以在逆序度较少的情况下达到线性复杂度,缺点是对于大规模数据排序效率不高。

func InsertionSort(data []interface{}, less func(a, b interface{}) bool) {
    n := len(data)
    for i := 1; i < n; i++ {
        for j := i; j > 0 && less(data[j], data[j-1]); j-- {
            data[j], data[j-1] = data[j-1], data[j]
        }
    }
}

3. 选择排序

选择排序的基本思想是每次选择待排序序列中的最小元素,然后将它与待排序序列的第一个元素交换位置,使得第一个元素为已排序序列的最小值。然后再从剩余的元素中选择最小值,交换到已排序序列的下一个位置。以此类推,直到整个序列排序完成。选择排序的时间复杂度为 O(n^2),空间复杂度为O(1)。选择排序的优点是简单易懂,实现简单,缺点是效率低下,对于大规模数据排序不适用。

func SelectionSort(data []interface{}, less func(a, b interface{}) bool) {
    n := len(data)
    for i := 0; i < n-1; i++ {
        minIdx := i
        for j := i + 1; j < n; j++ {
            if less(data[j], data[minIdx]) {
                minIdx = j
            }
        }
        data[i], data[minIdx] = data[minIdx], data[i]
    }
}

4. 快速排序

快速排序是一种高效的排序算法,其基本思想是通过一趟排序将待排序序列分割成两部分,其中一部分的所有元素都比另一部分的所有元素小。然后再对这两部分分别递归进行快速排序,直到整个序列有序。快速排序的时间复杂度为 O(n \log n),空间复杂度为 O(log n)。快速排序的优点是实现简单,性能优异,对于大规模数据排序效率非常高,缺点是在最坏情况下时间复杂度退化为 O(n^2),需要采用优化措施来避免。

func QuickSort(data []interface{}, less func(a, b interface{}) bool) {
    if len(data) < 2 {
        return
    }
    pivot := data[0]
    left, right := 1, len(data)-1
    for left <= right {
        for left <= right && less(data[left], pivot) {
            left++
        }
        for left <= right && !less(data[right], pivot) {
            right--
        }
        if left < right {
            data[left], data[right] = data[right], data[left]
            left++
            right--
        }
    }
    data[0], data[right] = data[right], data[0]
    QuickSort(data[:right], less)
    QuickSort(data[right+1:], less)
}

5. 归并排序

归并排序是一种稳定的排序算法,其基本思想是将待排序序列分成两部分,分别对每一部分递归进行排序,然后将排好序的两部分合并成一个有序序列。归并排序的时间复杂度为 O(n \log n),空间复杂度为 O(n)。归并排序的缺点是需要额外的内存空间来存储临时数据,但是在现代计算机的内存越来越大的情况下,这个缺点已经不再是一个大问题了。相比于快速排序,归并排序的性能相对较差,但是它在最坏情况下的时间复杂度仍然能够保持在 O(n \log n),因此归并排序是一种非常稳定和可靠的排序算法。

func MergeSort(data []interface{}, less func(a, b interface{}) bool) {
    if len(data) < 2 {
        return
    }
    mid := len(data) / 2
    MergeSort(data[:mid], less)
    MergeSort(data[mid:], less)
    tmp := make([]interface{}, len(data))
    copy(tmp, data)
    i, j, k := 0, mid, 0
    for i < mid && j < len(data) {
        if less(tmp[i], tmp[j]) {
            data[k] = tmp[i]
            i++
        } else {
            data[k] = tmp[j]
            j++
        }
        k++
    }
    for i < mid {
        data[k] = tmp[i]
        i++
        k++
    }
    for j < len(data) {
        data[k] = tmp[j]
        j++
        k++
    }
}

6. 堆排序

堆排序的时间复杂度为 O(n \log n),空间复杂度为 O(1)。堆排序的优点是不需要额外的内存空间,因为堆可以被存储在原数组中,因此空间复杂度非常低。堆排序的缺点是相对于其他排序算法,堆排序的常数因子比较大,因此在小规模数据的情况下,堆排序的性能可能不如其他排序算法。此外,由于堆排序需要进行大量的交换操作,因此其时间复杂度虽然为O(n \log n),但是在实际应用中,其性能可能比归并排序和快速排序稍差一些。

func HeapSort(data []interface{}, less func(a, b interface{}) bool) {
    n := len(data)
    for i := n/2 - 1; i >= 0; i-- {
        heapify(data, i, n, less)
    }
    for i := n - 1; i > 0; i-- {
        data[0], data[i] = data[i], data[0]
        heapify(data, 0, i, less)
    }
}

func heapify(data []interface{}, i, n int, less func(a, b interface{}) bool) {
    for {
        left := 2*i + 1
        right := 2*i + 2
        largest := i
        if left < n && less(data[largest], data[left]) {
            largest = left
        }
        if right < n && less(data[largest], data[right]) {
            largest = right
        }
        if largest == i {
            break
        }
        data[i], data[largest] = data[largest], data[i]
        i = largest
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

upcase

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值