Go常用算法集锦

前言

在日常开发中,我们经常会遇到一些针对复杂数据的处理,这时我们就会针对不同的业务使用不同算法,减少代码的逻辑复杂度,增加项目的可维护性,而为了保障项目的可持续性,一般都会进行算法的封装,当需要使用时,直接调用即可,这里为大家介绍一些常用的基础算法,以供各位大家参考,若有不对或者遗漏之处,欢迎评论区指出。

常用算法集锦

当然,为了更深入地理解深度优先搜索(DFS)和广度优先搜索(BFS),我们可以从基本概念出发,然后通过一个具体的图搜索问题来展示这两种算法的实现。

基本概念

在Go语言中,实现常用算法可以帮助你更好地理解编程逻辑和数据结构。以下是一些常用算法的示例,包括它们的实现过程和代码示例:

  1. 斐波那契数列

    • 描述:斐波那契数列是一系列数字,其中每个数字是前两个数字的和。
    • 实现:可以使用递归或迭代方法实现。
    • 代码示例(迭代):
      func fibonacci(n int) int {
          if n <= 1 {
              return n
          }
          a, b := 0, 1
          for i := 2; i <= n; i++ {
              a, b = b, a+b
          }
          return b
      }
      
  2. 二分查找
    在这里插入图片描述

    • 描述:在有序数组中查找某个目标值的位置。
    • 实现:通过每次将查找范围缩小一半来查找目标值。
    • 代码示例:
      func binarySearch(arr []int, target int) int {
          left, right := 0, len(arr)-1
          for left <= right {
              mid := left + (right-left)/2
              if arr[mid] == target {
                  return mid
              } else if arr[mid] < target {
                  left = mid + 1
              } else {
                  right = mid - 1
              }
          }
          return -1
      }
      
  3. 冒泡排序

    • 描述:通过重复遍历数组,比较并交换相邻元素来排序。
    • 实现:每次遍历都将最大的元素“冒泡”到末尾。
    • 代码示例:
      func bubbleSort(arr []int) {
          n := len(arr)
          for i := 0; i < n-1; i++ {
              for j := 0; j < n-i-1; j++ {
                  if arr[j] > arr[j+1] {
                      arr[j], arr[j+1] = arr[j+1], arr[j]
                  }
              }
          }
      }
      
  4. 递归算法

    • 描述:通过函数自己调用自己来解决问题。
    • 实现:定义一个函数,在其内部调用自己。
    • 代码示例(计算阶乘):
      func factorial(n int) int {
          if n == 0 {
              return 1
          }
          return n * factorial(n-1)
      }
      
  5. 快速排序

    • 描述:一种分治法策略的排序算法,通过选择一个“基准”元素,将数组分为两个子数组。
    • 实现:递归地对子数组进行快速排序。
    • 代码示例:
      func quickSort(arr []int) {
          if len(arr) < 2 {
              return
          }
          left, right := 0, len(arr)-1
          for left < right {
              for left < right && arr[right] >= arr[0] {
                  right--
              }
              arr[left], arr[right] = arr[right], arr[left]
              for left < right && arr[left] <= arr[0] {
                  left++
              }
              arr[left], arr[right] = arr[right], arr[left]
          }
          arr[left], arr[0] = arr[0], arr[left]
          quickSort(arr[:left])
          quickSort(arr[left+1:])
      }
      
  6. 归并排序

    • 描述:将两个已排序的数组合并成一个更大的已排序数组。
    • 实现:递归地将数组分成更小的数组,直到每个数组只有一个元素,然后合并它们。
    • 代码示例:
      func mergeSort(arr []int) []int {
          if len(arr) < 2 {
              return arr
          }
          mid := len(arr) / 2
          left := mergeSort(arr[:mid])
          right := mergeSort(arr[mid:])
      
          var i, j int
          var result []int
          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++
              }
          }
          return append(append(result, left[i:]...), right[j:]...)
      }
      
  7. 深度优先搜索(DFS)

    • 描述:用于遍历或搜索树或图的算法。
    • 实现:从一个节点开始,尽可能深地搜索树的分支。
    • 代码示例(图的DFS):
      func dfs(graph map[int][]int, visited map[int]bool, node int) {
          visited[node] = true
          for _, neighbor := range graph[node] {
              if !visited[neighbor] {
                  dfs(graph, visited, neighbor)
              }
          }
      }
      
  8. 广度优先搜索(BFS)

    • 描述:从最近的节点开始,逐层遍历图的算法。
    • 实现:使用队列来存储每一层的节点。
    • 代码示例(图的BFS):
      func bfs(graph map[int][]int, start int) {
          visited := make(map[int]bool)
          queue := []int{start}
          visited[start] = true
      
          for len(queue) > 0 {
              current := queue[0]
              queue = queue[1:]
              for _, neighbor := range graph[current] {
                  if !visited[neighbor] {
                      visited[neighbor] = true
                      queue = append(queue, neighbor)
                  }
              }
          }
      }
      
  9. 动态规划

    • 描述:通过将复杂问题分解成更简单的子问题来解决。
    • 实现:存储子问题的解,避免重复计算。
    • 代码示例(0-1背包问题):
      func knapsack(W int, wt []int, val []int, n int) int {
          K := make([][]int, n+1)
          for i := range K {
              K[i] = make([]int, W+1)
          }
      
          for i := 0; i <= n; i++ {
              for w := 0; w <= W; w++ {
                  if i == 0 || w == 0 {
                      K[i][w] = 0
                  } else if wt[i-1] <= w {
                      K[i][w] = max(val[i-1]+K[i-1][w-wt[i-1]], K[i-1][w])
                  } else {
                      K[i][w] = K[i-1][w]
                  }
              }
          }
          return K[n][W]
      }
      
  10. 图的最小生成树(Prim算法)

    • 描述:在图的边权重的条件下,构造一棵权重最小的生成树。
    • 实现:从一个节点开始,逐步添加最小权重的边。
    • 代码示例:
      func prim(graph [][]int) []int {
          n := len(graph)
          visited := make([]bool, n)
          edges := make([][]int, n)
          for i := range edges {
              edges[i] = []int{math.MaxInt32, i}
          }
          edges[0][0] = 0
      
          for i := 0; i < n; i++ {
              min := math.MaxInt32
              u := 0
              for j, visitedNode := range visited {
                  if edges[j][0] < min && !visitedNode {
                      min = edges[j][0]
                      u = j
                  }
              }
      
              visited[u] = true
              for v := 0; v < n; v++ {
                  if graph[u][v] > 0 && !visited[v] && graph[u][v] < edges[v][0] {
                      edges[v] = []int{graph[u][v], v}
                  }
              }
          }
      
          result := 0
          for _, edge := range edges {
              result += edge[0]
          }
          return result
      }
      
  11. 迪杰斯特拉算法(Dijkstra)

    • 描述:计算图中单个源点到其他所有顶点的最短路径。
    • 实现:使用优先队列和最小距离数组。
    • 代码示例:
      func dijkstra(graph [][]int, src int) []int {
          rows := len(graph)
          dist := make([]int, rows)
          for i := range dist {
              dist[i] = math.MaxInt32
          }
          dist[src] = 0
          visited := make([]bool, rows)
      
          for i := 0; i < rows; i++ {
              min := math.MaxInt32
              u := 0
              for j, v := range visited {
                  if !v && dist[j] < min {
                      min = dist[j]
                      u = j
                  }
              }
      
      visited[u] = true
              for v := 0; v < rows; v++ {
                  if !visited[v] && graph[u][v] > 0 && dist[u]+graph[u][v] < dist[v] {
                      dist[v] = dist[u] + graph[u][v]
                  }
              }
          }
          return dist
      }
      
  12. 字符串匹配算法(KMP算法)

    • 描述:在文本主串中搜索一个模式字符串的出现。
    • 实现:通过预处理模式字符串构建部分匹配表(PI表),提高搜索效率。
    • 代码示例:
      func KMPSearch(pat string, txt string) int {
          M := len(pat)
          N := len(txt)
          pi := computeLPSArray(pat, M)
          i := 0 // index for txt
          j := 0 // index for pat
          for i < N {
              if pat[j] == txt[i] {
                  i++
                  j++
              }
              if j == M {
                  return i - j
              } else if i < N && pat[j] != txt[i] {
                  if j != 0 {
                      j = pi[j-1]
                  } else {
                      i++
                  }
              }
          }
          return -1
      }
      
      func computeLPSArray(pat string, M int) []int {
          lps := make([]int, M)
          length := 0
          lps[0] = 0
          i := 1
          while i < M {
              if pat[i] == pat[length] {
                  length++
                  lps[i] = length
                  i++
              } else {
                  if length != 0 {
                      length = lps[length-1]
                  } else {
                      lps[i] = 0
                      i++
                  }
              }
          }
          return lps
      }
      

这些算法在Go语言中的实现只是基本示例,实际应用中可能需要根据具体情况进行调整和优化。

  1. 选择排序(Selection Sort)
  • 工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
package main

import "fmt"

// selectionSort 对切片进行选择排序
func selectionSort(arr []int) {
    n := len(arr)
    for i := 0; i < n-1; i++ {
        // 假设当前位置i是最小的索引
        minIndex := i
        // 遍历未排序的元素,找到最小值的索引
        for j := i + 1; j < n; j++ {
            if arr[j] < arr[minIndex] {
                minIndex = j
            }
        }
        // 如果最小值不是当前位置,则交换它们
        if minIndex != i {
            arr[i], arr[minIndex] = arr[minIndex], arr[i]
        }
    }
}

func main() {
    arr := []int{64, 25, 12, 22, 11}
    fmt.Println("Original array:", arr)
    selectionSort(arr)
    fmt.Println("Sorted array:  ", arr)
}

详细了解一下DFS、BFS以及链表

  1. 链表(LinkedList)
    首先,我们定义一个简单的单向链表节点和链表结构。
package main

import "fmt"

// ListNode 定义链表节点
type ListNode struct {
    Val  int
    Next *ListNode
}

// LinkedList 定义链表
type LinkedList struct {
    Head *ListNode
}

// Append 向链表末尾添加元素
func (l *LinkedList) Append(val int) {
    newNode := &ListNode{Val: val}
    if l.Head == nil {
        l.Head = newNode
    } else {
        current := l.Head
        for current.Next != nil {
            current = current.Next
        }
        current.Next = newNode
    }
}

// Print 打印链表
func (l *LinkedList) Print() {
    current := l.Head
    for current != nil {
        fmt.Print(current.Val, " ")
        current = current.Next
    }
    fmt.Println()
}

func main() {
    ll := &LinkedList{}
    ll.Append(1)
    ll.Append(2)
    ll.Append(3)
    ll.Print() // 输出: 1 2 3
}
  1. 深度优先搜索(DFS)

是一种用于遍历或搜索树或图的算法。它沿着树的深度遍历树的节点,尽可能深地搜索树的分支。在图中,这意味着尽可能深地探索从当前节点开始的路径,直到达到图的末端(即没有更多的邻居节点可以访问),然后回溯到上一个节点并尝试其他路径。

package main

import "fmt"

// Graph 以邻接表形式表示图
type Graph map[int][]int

// DFS 深度优先搜索
func DFS(graph Graph, start int, visited map[int]bool) {
    visited[start] = true
    fmt.Print(start, " ")
    for _, neighbor := range graph[start] {
        if !visited[neighbor] {
            DFS(graph, neighbor, visited)
        }
    }
}

func main() {
    graph := Graph{
        0: []int{1, 2},
        1: []int{2},
        2: []int{0, 3},
        3: []int{3},
    }
    visited := make(map[int]bool)
    DFS(graph, 0, visited) // 输出可能包括: 0 1 2 3(具体顺序取决于递归调用的栈)
}
  1. 广度优先搜索(BFS)

是另一种用于遍历或搜索树或图的算法。它从根节点开始,探索所有相邻的节点,然后再对每个相邻节点执行相同的操作,即先访问最近的节点,然后逐渐向外层扩展。在图中,这通常通过维护一个队列来实现,队列中保存了待访问的节点。。

package main

import (
    "container/list"
    "fmt"
)

// BFS 广度优先搜索
func BFS(graph Graph, start int) {
    visited := make(map[int]bool)
    queue := list.New()
    queue.PushBack(start)
    visited[start] = true

    for queue.Len() > 0 {
        front := queue.Remove(queue.Front()).(int)
        fmt.Print(front, " ")

        for _, neighbor := range graph[front] {
            if !visited[neighbor] {
                queue.PushBack(neighbor)
                visited[neighbor] = true
            }
        }
    }
}

func main() {
    graph := Graph{
        0: []int{1, 2},
        1: []int{2},
        2: []int{0, 3},
        3: []int{3},
    }
    BFS(graph, 0) // 输出: 0 1 2 3(具体顺序取决于队列的FIFO特性)
}

以上代码分别实现了链表的基本操作、图的深度优先搜索和广度优先搜索。这些是实现图论算法和数据结构操作的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bobo-rs

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

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

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

打赏作者

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

抵扣说明:

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

余额充值