{"id":26282946,"url":"https://github.com/kurt-steiner/datastructure.jl","last_synced_at":"2025-08-19T23:09:02.668Z","repository":{"id":221155089,"uuid":"753576803","full_name":"kurt-steiner/DataStructure.jl","owner":"kurt-steiner","description":"[Developing] 算法导论 Julia 实现，数据结构部分","archived":false,"fork":false,"pushed_at":"2024-09-23T16:04:07.000Z","size":41,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-14T12:36:10.743Z","etag":null,"topics":["datastructures","julia","julia-language"],"latest_commit_sha":null,"homepage":"","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kurt-steiner.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-06T11:56:07.000Z","updated_at":"2024-11-14T03:35:34.000Z","dependencies_parsed_at":"2024-11-21T08:36:04.436Z","dependency_job_id":null,"html_url":"https://github.com/kurt-steiner/DataStructure.jl","commit_stats":null,"previous_names":["nesteiner/linkedlist2.jl","kurt-steiner/datastructure.jl"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kurt-steiner/DataStructure.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurt-steiner%2FDataStructure.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurt-steiner%2FDataStructure.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurt-steiner%2FDataStructure.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurt-steiner%2FDataStructure.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kurt-steiner","download_url":"https://codeload.github.com/kurt-steiner/DataStructure.jl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurt-steiner%2FDataStructure.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271236280,"owners_count":24723978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-19T02:00:09.176Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["datastructures","julia","julia-language"],"created_at":"2025-03-14T17:16:04.788Z","updated_at":"2025-08-19T23:09:02.644Z","avatar_url":"https://github.com/kurt-steiner.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+title: 数据结构与算法\n\n* Graph\n** 遍历\n#+begin_src julia-ts\n  mutable struct BFSIterator{T}\n      graph::AbstractGraph{T}\n      start::Union{AdjList{T}, Nothing}\n  end\n\n  mutable struct DFSIterator{T}\n      graph::AbstractGraph{T}\n      start::Union{AdjList{T}, Nothing}\n  end\n\n  # 这里 nothing 表示默认将开始结点设置为领结表的第一个元素中的结点\n  BFSIterator(graph::AbstractGraph{T}, start::Union{AdjList{T}, Nothing}) where T = BFSIterator(graph, start)\n\n  DFSIterator(graph::AbstractGraph{T}, start::Union{AdjList{T}, Nothing}) where T = DFSIterator(graph, start)\n\n  @enum Color begin\n      White\n      Grey\n      Black\n  end\n\n  mutable struct BFSState{T}\n      queue::List{T}\n      visited::Dict{T, Color}\n  end\n\n  mutable struct DFSState{T}\n      stack::List{T}\n      visited::Dict{T, Color}\n  end\n#+end_src\n\n*** 广度优先遍历\n1. 首先创建一个 =Dict{VertexType, Color}= 映射集，并将所有结点的颜色设置为百色，表示未对其进行访问\n2. 创建一个队列 =queue= 来存放结点\n3. 选取一个开始结点 =startVertex=\n4. 提前将 =startVertex= 的颜色改为黑色，表示已经访问了该结点，并将其边结点放入了队列中\n5. 遍历 =startVertex= 的边结点，将他们插入到 =queue= 中\n6. 从 =queue= 中提取出一个元素作为开始结点 =vertex=\n7. 若这个 =vertex= 结点的颜色不是黑色，那么遍历其边结点\n   - 如果边结点的颜色是白色，那么将边结点插入到 =queue= 中\n   - 并将其颜色设置为灰色，表示虽然访问过该结点，但是还没访问过其边结点\n\n\n#+begin_src julia-ts\n  function iterate(iterator::BFSIterator{T}) where T\n      state = BFSState{T}(List(T), Dict{T, Color}())\n\n      if vertexCount(iterator.graph) == 0\n          return nothing\n      end\n\n      for adjList in iterator.graph.adjLists\n          vertex = adjList.vertex\n          state.visited[vertex] = White\n      end\n\n      firstVertex = if isnothing(iterator.start)\n          first(iterator.graph.adjLists).vertex\n      else\n          iterator.start.vertex\n      end\n\n      state.visited[firstVertex] = Black\n      edges = findEdges(iterator.graph, firstVertex)\n\n      for edge in edges\n          push!(state.queue, edge.vertex)\n          state.visited[edge.vertex] = Grey\n      end\n\n      return firstVertex, state\n  end\n\n  function iterate(iterator::BFSIterator{T}, state::BFSState{T}) where T\n      isempty(state.queue) \u0026\u0026 return nothing\n\n      vertex = popfirst!(state.queue)\n\n      if state.visited[vertex] != Black\n          edges = findEdges(iterator.graph, vertex)\n\n          for edge in edges\n              if state.visited[edge.vertex] == White\n                  push!(state.queue, edge.vertex)\n                  state.visited[edge.vertex] = Grey\n              end\n          end\n\n          state.visited[vertex] = Black\n      end\n\n      return vertex, state\n  end\n#+end_src\n*** 深度优先遍历\n1. 创建一个 =Dict{VertexType, Color}= 映射集，并将所有结点的颜色设置为白色，\n2. 创建一个栈 =stack= 来存放结点\n3. 选取一个开始结点 =startVertex=\n4. 提前将 =startVertex= 的颜色改为黑色，表示已访问了该结点，并将其边结点放入了栈中\n5. 遍历 =startVertex= 的边结点，将其颜色改为灰色，表示已访问该结点，但是还没有访问其边结点\n6. 从 =stack= 中提取一个元素作为开始结点 =vertex=\n7. 遍历 =vertex= 的边结点，如果边结点的颜色为白色，那么插入边结点到 =stack= 中，并将其颜色设置为灰色\n\n#+begin_src julia-ts\n  function iterate(iterator::DFSIterator{T}) where T\n      state = DFSState{T}(List(T), Dict{T, Color}())\n\n      if vertexCount(iterator.graph) == 0\n          return nothing\n      end\n\n      firstVertex = if isnothing(iterator.start)\n          first(iterator.graph.adjLists).vertex\n      else\n          iterator.start.vertex\n      end\n\n      for adjList in iterator.graph.adjLists\n          vertex = adjList.vertex\n          state.visited[vertex] = White\n      end\n\n      state.visited[firstVertex] = Black\n\n      for edge in findEdges(iterator.graph, firstVertex)\n          push!(state.stack, edge.vertex)\n          state.visited[edge.vertex] = Grey\n      end\n\n      return firstVertex, state\n  end\n\n  function iterate(iterator::DFSIterator{T}, state::DFSState{T}) where T\n      isempty(state.stack) \u0026\u0026 return nothing\n\n      vertex = pop!(state.stack)\n\n      for edge in findEdges(iterator.graph, vertex)\n          if state.visited[edge.vertex] == White\n              push!(state.stack, edge.vertex)\n              state.visited[edge.vertex] = Grey\n          end\n      end\n\n      return vertex, state\n  end\n#+end_src\n\n这里可以不用颜色来表示每个点的状态，用 =Dict{VertexType, Bool}= 也行的\n** 最小生成树\n*** kruskal 算法\n=kruskal= 算法关注的是边，在我的算法实现里他首先定义了一个结构体来记录边的信息\n#+begin_src julia-ts\n  @kwdef struct RecordItem{T}\n      start::T\n      endat::T\n      weight::Number    \n  end\n#+end_src\n\n这个算法的思路是\n1. 遍历整个图 =graph= ，将所有边的信息汇集到一个数组 =record= 中\n2. 将这个数组以结构体中 =weight= 为关键字进行排序\n3. 创建一个空图 =result= 作为结果，将所有点插入到 =result= 中\n4. 在一个循环里对 =result= 插入边\n   - 首先我们要确认，当 =result.edgeCount= 为 =graph.vertexCount - 1= 时，生成树已经创建完成，此时该退出循环\n   - 如果插入边后图中有环，那么删除刚才插入的边\n\n#+begin_src julia-ts\n  function kruskal(graph::AbstractGraph{T}, start::Union{T, Nothing} = nothing) where T\n      startVertex = if isnothing(start)\n          if graph.vertexCount == 0\n              nothing\n          else\n              first(graph.adjLists).vertex\n          end\n      else\n          findfirst(adjList -\u003e adjList.vertex == start, graph.adjLists)\n      end\n\n      if isnothing(startVertex)\n          throw(BadOperationException(\"cannot start from a non-exist vertex\"))\n      end\n\n      record = RecordItem{T}[]\n      visited = Dict{T, Color}()\n\n      for adjList in graph.adjLists\n          visited[adjList.vertex] = White\n      end\n\n      for adjList in graph.adjLists\n          vertex = adjList.vertex\n\n          if visited[vertex] == Black\n              continue\n          end\n        \n          edges = adjList.edges\n\n          visited[vertex] = Grey\n\n          start = vertex\n        \n          for edge in edges\n              endat = edge.vertex\n              visited[endat] = Grey\n\n              push!(record, RecordItem(start = start, endat = endat, weight = edge.weight))\n          end\n\n          visited[vertex] = Black\n      end\n\n      sort!(record, by = item -\u003e item.weight)\n\n      result = if isa(graph, DirectedGraph)\n          DirectedGraph(T)\n      else\n          UnDirectedGraph(T)\n      end\n\n      for adjList in graph.adjLists\n          insertVertex!(result, adjList.vertex)\n      end\n\n      index = 1\n      len = length(record)\n\n      while result.edgeCount != graph.vertexCount - 1 \u0026\u0026 index \u003c= len\n          item = record[index]\n\n          if !hasEdge(result, item.start, item.endat)\n              insertEdge!(result, item.start, item.endat, item.weight)\n          end\n\n          if hasCycle(result)\n              removeEdge!(result, item.start, item.endat)\n          end\n\n          index += 1\n      end\n\n      return result\n  end\n\n#+end_src     \n*** prim 算法\n=prim= 的核心是，将点集分为两个集合，在两个集合中找出最短的相邻的边，将边插入\n1. prim 算法在我的实现中需要两个辅助映射集\n   - =visisted::Dict{T, Bool}= 表示结点是否访问过，将其看做划分点集的记录\n   - =parents::Dict{T, Union{T, Nothing}}= 表示结点的父结点，如果是 =nothing= 则表示没有父结点\n2. 创建一个空图 =result= ，用来作为结果返回\n3. 遍历函数参数 =graph= ，我们只使用邻接表中的点\n   - =visited[adjList.vertex] = false=\n   - =parents[adjList.vertex] = nothing=\n   - 将点插入到 =result= 中\n4. 选取一个起始点 =startVertex= ，将 =startVertex= 划分为已访问过的点集\n5. 在一个循环中\n   - 直到所有结点已被访问才退出循环\n   - 在所有未访问的点集和已访问的点集中寻找最小的权重边和对应的两个点，并设置对应的父子关系\n   - 插入父结点和子结点对应的边，权重为最小权重边\n   - 设置父结点已被访问过\n\n#+begin_src julia-ts\n  function prim(graph::AbstractGraph{T}, start::Union{T, Nothing} = nothing) where T\n      startVertex = if isnothing(start)\n          if graph.vertexCount == 0\n              nothing\n          else\n              first(graph.adjLists).vertex\n          end\n      else\n          findfirst(adjList -\u003e adjList.vertex == start, graph.adjLists)\n      end\n\n      if isnothing(startVertex)\n          throw(BadOperationException(\"cannot start from a non-exist vertex\"))\n      end\n\n      result::AbstractGraph{T} = if isa(graph, UnDirectedGraph) \n          UnDirectedGraph(T)\n      else\n          DirectedGraph(T)\n      end\n\n      # 标记点集，被标记的相当于加入了点集中    \n      visited = Dict{T, Bool}()\n      parents = Dict{T, Union{T, Nothing}}()\n      for adjList in graph.adjLists\n          visited[adjList.vertex] = false\n          parents[adjList.vertex] = nothing\n          insertVertex!(result, adjList.vertex)\n      end\n\n      visited[startVertex] = true\n    \n      while !all(values(visited))\n          minVertex, minWeight = nothing, Inf\n          # 所有未访问过的点集\n          for adjList in graph.adjLists\n              if visited[adjList.vertex]\n                  continue\n              end\n\n              for edge in adjList.edges\n                  # 未访问过的点集和已访问过的点集之间的边\n                  if visited[edge.vertex]\n                      if minWeight \u003e edge.weight\n                          # minVertex, minWeight = edge.vertex, edge.weight\n                          minVertex = edge.vertex\n                          minWeight = edge.weight\n                          parents[edge.vertex] = adjList.vertex\n                      end\n                  end\n              end\n\n          end\n\n          insertEdge!(result, parents[minVertex], minVertex, minWeight)\n          visited[parents[minVertex]] = true\n      end\n\n      return result\n  end\n#+end_src\n\n** 最短路径\n*** Dijkstra 算法\n给定一个图 =graph= 一个起始点，可以得出这个点到每个点的距离，并附带每个结点的父结点\n1. 首先进行初始化\n   - 给定一个记录起始点到其他结点的权重 =distanceMap=\n   - 给定一个记录父结点的映射集 =parents=\n   - 给定一个记录每个结点访问记录的 =visited=\n   - 将每个结点的 =distance= 设置为 =Inf=\n   - 将每个结点的 =parent= 设置为 =nothing=\n   - 将每个结点的 =visited= 设置为 =false=\n\n2. 给定一个起始结点，将到其的权重设置为 0\n\n3. 在一个循环中\n   - 当所有结点已被访问时，退出循环\n   - 提取其结点未被访问过的邻接表，找出其中的点在 =distanceMap= 中最小的邻接表 =minAdjList=\n   - 遍历 =minAdjList= 的边，比较\n     1. 到这个边的距离 *A*\n     2. 到最小点(最小邻接表)的距离 + 边的权重 *B*\n     3. 如果 *A* \u003e *B* ，那么将到边结点的距离设置为 *B* ，并将边结点的 =parent= 设置为最小结点 \n\n   - 将最小点设置为已访问过        \n\n   \n#+begin_src julia-ts\n  mutable struct DijkstraShortestPath{T}\n      graph::AbstractGraph{T}\n      start::T\n      distancesMap::Dict{T, Number}\n      parents::Dict{T, Union{T, Nothing}}\n      visited::Dict{T, Bool}\n  end\n\n\n  function DijkstraShortestPath(graph::AbstractGraph{T}, start::T) where T\n      result = DijkstraShortestPath(graph, start, Dict{T, Number}(), Dict{T, Union{T, Nothing}}(), Dict{T, Bool}())\n\n      distancesMap = result.distancesMap\n      parents = result.parents\n      graph = result.graph\n      visited = result.visited\n\n      for adjList in graph.adjLists\n          distancesMap[adjList.vertex] = Inf\n          parents[adjList.vertex] = nothing\n          visited[adjList.vertex] = false\n      end\n\n      distancesMap[start] = 0\n\n      while !all(values(visited))\n          minAdjList = reduce(\n              (left, right) -\u003e distancesMap[left.vertex] \u003c distancesMap[right.vertex] ? left : right,\n              filter(adjList -\u003e !visited[adjList.vertex], graph.adjLists)\n          )\n\n          minVertex = minAdjList.vertex\n          edges = minAdjList.edges\n          # visited[minVertex] = true\n\n          for edge in edges\n              value = distancesMap[minVertex] + edge.weight\n              if distancesMap[edge.vertex] \u003e value\n                  distancesMap[edge.vertex] = value\n                  parents[edge.vertex] = minVertex\n              end\n          end\n\n          visited[minVertex] = true\n        \n      end\n\n      return result\n  end\n#+end_src        \n        \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkurt-steiner%2Fdatastructure.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkurt-steiner%2Fdatastructure.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkurt-steiner%2Fdatastructure.jl/lists"}