这是去年做的轮子,现在学函数式编程挺久了,有空想重新构造下代码。
顺便说一下,当初学元编程不怎么会,宏写得不怎么好
# graph.jl
include("List.jl")
import .LinkedList:Queue
import .LinkedList:push
import .LinkedList:remove
import .LinkedList:@lengthof
#--------------------------------#
# vertex #
#--------------------------------#
@enum Color White=0 Grey=1 Black=2
mutable struct Vertex{T}
value::T
color::Color
index::UInt64
hop::Int
end
Vertex{T}(value::T) where T = Vertex{T}(value,White,0,0)
#----------------#
# == #
#----------------#
Base.:(==)(vertex1::Vertex{T},vertex2::Vertex{T}) where T = vertex1.value == vertex2.value
#----------------#
# valueof #
#----------------#
valueof(vertex::Vertex{T}) where T = vertex.value
#----------------#
# indexof #
#----------------#
indexof(vertex::Vertex{T}) where T = vertex.index
setindex(vertex::Vertex{T},index::UInt64) where T = vertex.index=index
isvisted(vertex::Vertex{T}) where T = !(notvisited(vertex))
visited!(vertex::Vertex{T}) where T = vertex.color=Black
notvisited(vertex::Vertex{T}) where T = vertex.color == White
# export Vertex
# export Color
# export White
# export Black
# export Grey
# export ==
# export valueof
# export indexof
# export setindex
# end
#--------------------------------#
# adjlist #
#--------------------------------#
#module adjlist
#import ..vertex:Vertex
mutable struct AdjList{T}
vertex::Vertex{T}
edge::Set{Tuple{Vertex{T},Int}} #contain vertex and weight
end
AdjList{T}(value::T) where T = AdjList{T}(Vertex{T}(value),Set{Tuple{Vertex{T},Int}}())
#Base.iterate(adjlist::AdjList{T}) where T = (adjlist.vertex,adjlist.edge)
#----------------#
# vertex-of #
#----------------#
vertexof(adjlist::AdjList{T}) where T = adjlist.vertex
#----------------#
# edge-of #
#----------------#
# export AdjList
# export vertexof
#export iterate
#end
#--------------------------------#
# graph #
#--------------------------------#
#module graph
# import ..vertex:Vertex
# import ..vertex:indexof
# import ..adjlist:vertexof
# import ..adjlist:AdjList
mutable struct Graph{T}
vcount::Int
ecount::Int
list::Set{AdjList{T}}
hasdirection::Bool
end
Graph{T}(direct=true) where T = Graph{T}(0,0,Set{AdjList{T}}(),direct)
#----------------#
# vertexof #
#----------------#
vertexof(graph::Graph{T},index::UInt64) where T =
begin
for current in graph.list
if indexof(current.vertex) == index
return current.vertex
end
end
end
#----------------#
# getadjlist #
#----------------#
getadjlist(graph::Graph{T},index::UInt64) where T = begin
for current in graph.list #AdjList
if indexof(vertexof(current)) == index
return current
end
end
end
# export Graph
# export getadjlist
# end
#--------------------------------#
# function #
#--------------------------------#
# using .vertex
# using .adjlist
# using .graph
#----------------#
# edgeof #
#----------------#
edgeof(graph::Graph{T},index::UInt64) where T = begin
adjlist=getadjlist(graph,index)
if adjlist != nothing
adjlist.edge
end
end
edgeof(adjlist::AdjList{T}) where T = adjlist.edge
#--------------------------------#
# append #
#--------------------------------#
#------------------------#
# add vertex -> index #
#------------------------#
function append_vertex!(graph::Graph{T},value::T) where T# return index
for adjlist in graph.list #AdjList
if value == valueof(vertexof(adjlist))
return
end
end
new_elmt = AdjList{T}(value)
index=hash(value)
graph.vcount+=1
setindex(vertexof(new_elmt),index)
push!(graph.list,new_elmt)
index
end
#------------------------#
#add egde with two index #
#------------------------#
function append_edge!(graph::Graph{T},index1::UInt64,index2::UInt64,w::Int=0) where T# w: 权重
#judge that if index1 and index2 is in each vertex of graph.list(AdjList)
adjlist1=getadjlist(graph,index1)
adjlist2=getadjlist(graph,index2)
if adjlist1 == nothing || adjlist2 == nothing
return
end
if graph.hasdirection == true
push!(edgeof(adjlist1),(vertexof(adjlist2),w))
else
push!(edgeof(adjlist1),(vertexof(adjlist2),w))
push!(edgeof(adjlist2),(vertexof(adjlist1),w))
end
graph.ecount+=1
end
这是List.jl
module LinkedList
abstract type SingleList{T} end
#----------------#
# ListElmt #
#----------------#
mutable struct ListElmt{T}
value::T
next::Union{Nothing,ListElmt{T}}
end
ListElmt{T}(data::T) where T = ListElmt{T}(data,nothing)
#----------------#
# DListElmt #
#----------------#
mutable struct DListElmt{T}
value::T
prev::Union{Nothing,DListElmt{T}}
next::Union{Nothing,DListElmt{T}}
end
DListElmt{T}(data::T) where T = DListElmt{T}(data,nothing,nothing)
#----------------#
# mode #
#----------------#
struct Mode
push_fn::Int
pop_fn::Int
end
const Push_Front=0
const Push_Back=1
const Pop_Front=2
const Pop_Back=3
#-------------------#
# List #
#-------------------#
mutable struct List{T} <: SingleList{T}
size::Int
head::Union{Nothing,ListElmt{T}}
tail::Union{Nothing,ListElmt{T}}
mode::Mode
end
List{T}() where T = List{T}(0,nothing,nothing,Mode(Push_Back,Pop_Back))
#------------------#
# DList #
#------------------#
mutable struct DList{T}
size::Int
head::Union{Nothing,DListElmt{T}}
tail::Union{Nothing,DListElmt{T}}
mode::Mode
end
DList{T}() where T = DList{T}(0,nothing,nothing,Mode(Push_Back,Pop_Back))
#------------------#
# Queue #
#------------------#
mutable struct Queue{T} <: SingleList{T}
size::Int
head::Union{Nothing,ListElmt{T}}
tail::Union{Nothing,ListElmt{T}}
mode::Mode
end
Queue{T}() where T = Queue{T}(0,nothing,nothing,Mode(Push_Back,Pop_Front))
#------------------#
# Stack #
#------------------#
mutable struct Stack{T} <: SingleList{T}
size::Int
head::Union{Nothing,ListElmt{T}}
tail::Union{Nothing,ListElmt{T}}
mode::Mode
end
Stack{T}() where T = Stack{T}(0,nothing,nothing,Mode(Push_Front,Pop_Front))
#----------------#
# macro #
#----------------#
# Q? is need for esc ??
macro lengthof(list)
quote
$list.size
end |> esc
end
macro valueof(elmt)
quote
$elmt.value
end |> esc
end
macro nextof(elmt)
quote
$elmt.next
end |> esc
end
#-----------------#
# push fn #
#-----------------#
function push_back(list::SingleList{T},data::T) where T
new_elmt=ListElmt{T}(data)
if 0 == @lengthof list
list.head=list.tail=new_elmt
else
list.tail=list.tail.next=new_elmt
end
list.size+=1
end
function push_back(list::DList{T},data::T) where T
new_elmt=DListElmt{T}(data)
if 0 == @lengthof list
list.head=list.tail=new_elmt
else
new_elmt.prev=list.tail
list.tail.next=new_elmt
list.tail=new_elmt
end
list.size+=1
end
function push_front(list::SingleList{T},data::T) where T
new_elmt=ListElmt{T}(data)
if 0 == @lengthof list
list.head=list.tail=new_elmt
else
new_elmt.next=list.head
list.head=new_elmt
end
list.size+=1
end
function push_front(list::DList{T},data::T) where T
new_elmt=DListElmt{T}(data)
if 0 == @lengthof list
list.head=list.tail=new_elmt
else
new_elmt.next=list.head
list.head.prev=new_elmt
list.head=new_elmt
end
list.size+=1
end
#--------------#
# pop fn #
#--------------#
function pop_back(list::SingleList{T}) where T
if list.size==0
return nothing
end
if list.size==1
res=list.head.value
list.head=list.tail=nothing
list.size-=1
return res
end
current=list.head
for i in 1:list.size-2
current=current.next
end
res=list.tail.value
list.tail=current
list.size-=1
res
end
function pop_back(list::DList{T}) where T
if list.size==0
return nothing
end
if list.size==1
res=list.head.value
list.head=list.tail=nothing
list.size-=1
return res
end
res=list.tail.value
list.tail=list.tail.prev
list.tail.next=nothing
list.size-=1
return res
end
function pop_front(list::SingleList{T}) where T
if list.size==0
return nothing
else
res=list.head.value
list.head=list.head.next
list.size-=1
return res
end
end
function pop_front(list::DList{T}) where T
if list.size==0
return nothing
else
res=list.head.value
list.head=list.head.next
list.head.prev=nothing
list.size-=1
return res
end
end
#---------------#
# interface #
#---------------#
function push(list::SingleList{T},data::T) where T
if list.mode.push_fn == Push_Front
push_front(list,data)
else
push_back(list,data)
end
end
function push(list::DList{T},data::T) where T
if list.mode.push_fn == Push_Front
push_front(list,data)
else
push_back(list,data)
end
end
function remove(list::SingleList{T}) where T
if list.mode.pop_fn == Pop_Back
return pop_back(list)
else
return pop_front(list)
end
end
function remove(list::DList{T}) where T
if list.mode.pop_fn == Pop_Back
return pop_back(list)
else
return pop_front(list)
end
end
#-----------------#
# iterate #
#-----------------#
Base.iterate(list::Union{SingleList{T},DList{T}}) where T = list.size==0 ? nothing : ( list.head, list.head)
Base.iterate(list::Union{SingleList{T},DList{T}},state::Union{ListElmt{T},DListElmt{T}}) where T = state.next==nothing ? nothing : ( state.next, state.next)
#--------------#
# appendix #
#--------------#
#--------------#
# contain #
#--------------#
function contain(list::Union{SingleList{T},DList{T}},data::T) where T
for current in list
if @valueof(current) == data
return true
end
end
return false
end
#--------------#
# print #
#--------------#
function Base.print(list::Union{SingleList{T},DList{T}}) where T
for current in list
print(@valueof(current),'\t')
end
println()
end
# export List
# export DList
# export Queue
# export Stack
# export contain
# export push
# export remove
# export print
end
dijkstra算法
# dijkstra.jl
include("graph.jl")
include("load_weight.jl")
#--------------------------------#
# Dijkstra #
#--------------------------------#
function dijkstra(graph::Graph{T},start::UInt64,last::UInt64) where T
weight=load_weight(graph)
for (k,v) in weight
println(k,'\t',v)
end
#need a list for save
list=Dict{UInt64,Int}()
#init list
for adjlist in graph.list
vertex=vertexof(adjlist)
list[indexof(vertex)] = abs(typemax(Int))
end
for (vertex,) in edgeof(graph,start)
list[indexof(vertex)] = weight[start][indexof(vertex)]
vertex.color = Grey
vertexof(graph,start).color = Black
end
for (minindex,) in list
if vertexof(graph,minindex).color == Grey
for (vertex,) in edgeof(graph,minindex)
if vertex.color != Black
list[indexof(vertex)]=min(list[indexof(vertex)],list[minindex]+weight[minindex][indexof(vertex)])
vertex.color = Grey
end
end
vertexof(graph,minindex).color = Black
end
end
return list[last]
end
index=Vector{UInt64}(undef,7)
graph=Graph{Int}()
for i in 1:7
index[i]=append_vertex!(graph,i)
end
append_edge!(graph,index[1],index[2],2)
append_edge!(graph,index[1],index[3],5)
append_edge!(graph,index[2],index[4],1)
append_edge!(graph,index[2],index[5],3)
append_edge!(graph,index[3],index[2],6)
append_edge!(graph,index[3],index[6],8)
append_edge!(graph,index[4],index[5],4)
append_edge!(graph,index[5],index[7],9)
append_edge!(graph,index[6],index[7],7)
res=dijkstra(graph,index[1],index[7])
print(res)
# load_weight.jl
#include("graph2.jl")
function load_weight(graph::Graph{T}) where T
dict=Dict{UInt64,Dict{UInt64,Int}}()
for adjlist in graph.list#Set of AdjList |vertex,Set{Tuple}|
vertex1,edge=vertexof(adjlist),edgeof(adjlist)
dict[indexof(vertex1)]=Dict{UInt64,Int}()
for (vertex2,weight) in edge
dict[indexof(vertex1)][indexof(vertex2)] = weight
end
end
return dict
end
weight(dict::Dict{UInt64,Dict{UInt64,Int}},index1::UInt64,index2::UInt64) = dict[index1][index2]