golang数据结构篇之分治法

简介: golang数据结构篇之分治法

思想

先分别处理局部,再合并结果。分而治之。

使用场景:

  • 快速排序
  • 归并排序
  • 二叉树相关问题

分治法模板

  1. 递归返回条件
  2. 分段处理
  3. 合并结果
func traversal(root *TreeNode) ResultType  {
    // nil or leaf
    if root == nil {
        // do something and return
    }
    // Divide
    ResultType left = traversal(root.Left)
    ResultType right = traversal(root.Right)
    // Conquer
    ResultType result = Merge from left and right
    return result
}


分治法遍历二叉树

func preorderTraversal(root *TreeNode) []int {
    result := divideAndConquer(root)
    return result
}
func divideAndConquer(root *TreeNode) []int {
    result := make([]int, 0)
    // 返回条件(null & leaf)
    if root == nil {
        return result
    }
    // 分治(Divide)
    left := divideAndConquer(root.Left)
    right := divideAndConquer(root.Right)
    // 合并结果(Conquer)
    result = append(result, root.Val)
    result = append(result, left...)
    result = append(result, right...)
    return result
}

归并排序

func MergeSort(nums []int) []int {
  return mergeSort(nums)
}
func mergeSort(nums []int) []int {
  if len(nums) <= 1 {
    return nums
  }
  // 分治法:divide 分为两段
  mid := len(nums) / 2
  left := mergeSort(nums[:mid])
  right := mergeSort(nums[mid:])
  // 合并两段数据
  result := merge(left, right)
  return result
}
func merge(left, right []int) (result []int) {
  // 两边数组合并游标
  l := 0
  r := 0
  // 注意不能越界
  for l < len(left) && r < len(right) {
    // 谁小合并谁
    if left[l] > right[r] {
      result = append(result, right[r])
      r++
    } else {
      result = append(result, left[l])
      l++
    }
  }
  // 剩余部分合并
  result = append(result, left[l:]...)
  result = append(result, right[r:]...)
  return
}

快排

func QuickSort(nums []int) []int {
    // 思路:把一个数组分为左右两段,左段小于右段,类似分治法没有合并过程
    quickSort(nums, 0, len(nums)-1)
    return nums
}
// 原地交换,所以传入交换索引
func quickSort(nums []int, start, end int) {
    if start < end {
        // 分治法:divide
        pivot := partition(nums, start, end)
        quickSort(nums, 0, pivot-1)
        quickSort(nums, pivot+1, end)
    }
}
// 分区
func partition(nums []int, start, end int) int {
    p := nums[end]
    i := start
    for j := start; j < end; j++ {
        if nums[j] < p {
            swap(nums, i, j)
            i++
        }
    }
    // 把中间的值换为用于比较的基准值
    swap(nums, i, end)
    return i
}
func swap(nums []int, i, j int) {
    t := nums[i]
    nums[i] = nums[j]
    nums[j] = t
}


堆排

package main
func HeapSort(a []int) []int {
  //将无序数组a构建为一个大根堆
  for i := len(a)/2 - 1; i >= 0; i-- {
    sink(a, i, len(a))
  }
  // 然后把前面这段数组继续下沉保持堆结构,如此循环即可
  for i := len(a) - 1; i >= 1; i-- {
    // 从后往前把数组变有序
    swap(a, 0, i)
    // 前面的长度减一,因为最后一个是有序的
    sink(a, 0, i)
  }
  return a
}
func sink(a []int, i int, length int) {
  for {
    // 左节点索引(从0开始,所以左节点为i*2+1)
    l := i*2 + 1
    // 右节点索引
    r := i*2 + 2
    // idx保存根、左、右三者之间较大值的索引
    idx := i
    // 存在左节点,左节点值较大,则取左节点
    if l < length && a[l] > a[idx] {
      idx = l
    }
    // 存在右节点,且值较大,取右节点
    if r < length && a[r] > a[idx] {
      idx = r
    }
    // 如果根节点较大,则不用下沉
    if idx == i {
      break
    }
    // 如果根节点较小,则交换值,并继续下沉
    swap(a, i, idx)
    // 继续下沉idx节点
    i = idx
  }
}
func swap(a []int, i, j int) {
  a[i], a[j] = a[j], a[i]
}

十大经典排序算法

十大经典排序算法(动图演示)


目录
相关文章
|
6月前
|
存储 算法 Go
Golang 数据结构:图
Golang 数据结构:图
92 0
|
6月前
|
Go
golang数据结构篇之二叉树
golang数据结构篇之二叉树
40 0
|
6月前
|
Go
golang数据结构篇之栈和队列以及简单标准库
golang数据结构篇之栈和队列以及简单标准库
76 0
|
2月前
|
算法 安全 测试技术
golang 栈数据结构的实现和应用
本文详细介绍了“栈”这一数据结构的特点,并用Golang实现栈。栈是一种FILO(First In Last Out,即先进后出或后进先出)的数据结构。文章展示了如何用slice和链表来实现栈,并通过golang benchmark测试了二者的性能差异。此外,还提供了几个使用栈结构解决的实际算法问题示例,如有效的括号匹配等。
golang 栈数据结构的实现和应用
|
6月前
|
Go
golang力扣leetcode 432.全O(1)的数据结构
golang力扣leetcode 432.全O(1)的数据结构
43 0
|
6月前
|
NoSQL Go Redis
golang数据结构篇之跳表
golang数据结构篇之跳表
50 0
|
6月前
|
Go
golang数据结构篇之二进制
golang数据结构篇之二进制
42 0
|
6月前
|
存储 算法 Java
Golang底层原理剖析之多路select、channel数据结构和阻塞与非阻塞
Golang底层原理剖析之多路select、channel数据结构和阻塞与非阻塞
85 0
|
Go Python 存储
Golang常用数据结构
数组 声明数组 数组同样使用倒置的方式来声明,并且声明数组的时候需要指定数组长度。所以声明数组需要使用[数组长度]类型的方式来声明,如果需要在声明的同时初始化,还可以添加{}初始化列表。
857 0
下一篇
无影云桌面