Как реализовать SingleLinkedList в Julia

#julia

#джулия

Вопрос:

Я изучаю TAD, но я не очень разбираюсь в синтаксисе, поэтому мне слишком сложно создать единый список, но я понимаю, как это работает, например, TAD, пожалуйста, кто-нибудь может рассказать, как реализовать этот TAD (связанный список), с основными инструкциями и описаниемони

 abstract type AbstractList{T} end
abstract type AbstractNode{T} end

mutable struct Nodo{T} <: AbstractNode{T}
    value ::T
    next ::Nodo{T}
    Nodo{T}() where T =(x=new();x;x.next=x)
    Nodo{T}(v,n) where T =new(v,n)
end

mutable struct LList{T} <: AbstractList{T}
    first ::Nodo{T}
    LList{T}() where T =new(Nodo{T}())
end

Lista=LList;

function Append(lista,value)
    current=Nodo(value,new(Nodo()))
    if Lista.size==0
        lista.head=current
    else
        MyNode=Lista.first;
        while MyNode.next!=nothing
            MyNode=MyNode.next;
        MyNode.next=current;
        end
    end
    Lista.size =1
end

Append(Lista,2)
  

Я пытаюсь это сделать, но я не знаю, почему это не работает, я запутался, потому что я читал много сообщений об инструкциях, которые я использовал, но я совсем не понимаю Nodo{T}() where T =(x=new();x;x.next=x) эту инструкцию, мне нужна помощь.

Комментарии:

1. Что означает «TAD»?

2. Я предположил, что ADT (абстрактный тип данных).

3. Ah, tipo abstracto de datos !

Ответ №1:

В вашем коде есть сочетание концепций, поэтому, чтобы помочь вам, я использую одну из них, чтобы показать вам, как вы можете реализовать свой связанный список. Вот код:

 abstract type AbstractList{T} end
abstract type AbstractNode{T} end

mutable struct Nodo{T} <: AbstractNode{T}
    value::T
    next::Union{Nodo{T}, Nothing}
end

mutable struct LList{T} <: AbstractList{T}
    head::Union{Nodo{T}, Nothing}
    LList{T}() where T = new{T}(nothing)
end

function Base.push!(lista::LList, value)
    new_nodo = Nodo(value, nothing)
    if isnothing(lista.head)
        lista.head = new_nodo
    else    
        current_nodo = lista.head
        while !isnothing(current_nodo.next)
            current_nodo = current_nodo.next
        end
        current_nodo.next = new_nodo
    end
    return lista
end
  

и вот как вы можете его использовать:

 julia> lista=LList{Int}()
LList{Int64}(nothing)

julia> push!(lista, 1)
LList{Int64}(Nodo{Int64}(1, nothing))

julia> push!(lista, 2)
LList{Int64}(Nodo{Int64}(1, Nodo{Int64}(2, nothing)))

julia> push!(lista, 3)
LList{Int64}(Nodo{Int64}(1, Nodo{Int64}(2, Nodo{Int64}(3, nothing))))
  

Некоторые комментарии:

  • Я использую Union , чтобы показать, что объект может либо не содержать ссылки ( Nothing ), либо какой-либо ссылки на следующий объект ( Nodo{T} )
  • В LList{T}() where T = new{T}(nothing) мы определяем только один внутренний конструктор, поскольку он не принимает аргументов, я использую new{T} его, доступный только во внутренних конструкторах, для создания экземпляра LList{T} объекта со значением, равным nothing (поскольку у него еще нет узлов)
  • Я использую Base.push! , поскольку это стандартное имя функции для добавления элемента в коллекцию; Base. необходимо для добавления метода в стандартную функцию; также поэтому позже я напишу lista::LList , чтобы убедиться, что этот метод специфичен для вашего LList{T} типа
  • как вы можете видеть в коде, нет необходимости в «фиктивном» узле (как это было в вашем коде), поскольку вы просто отслеживаете конец списка, используя nothing значение

Я надеюсь, что начиная с этого момента вы сможете добавлять другие методы к своему LList объекту.

Ответ №2:

Немного другая версия ответа Богумила заключается в использовании неопределенных полей.

 abstract type AbstractList{T} end
abstract type AbstractNode{T} end

mutable struct Nodo{T} <: AbstractNode{T}
    value::T
    next::Nodo{T}
    function Nodo(v::T) where T
        n = new{T}()
        n.value = v
        return n
    end
end

mutable struct LList{T} <: AbstractList{T}
    head::Nodo{T}
    LList{T}() where T = new{T}()
end

function Base.push!(lista::LList, value)
    new_nodo = Nodo(value)
    if isdefined(lista, :head)
        current_nodo = lista.head
        while isdefined(current_nodo, :next)
            current_nodo = current_nodo.next
        end
        current_nodo.next = new_nodo
    else
        lista.head = new_nodo
    end

    return lista
end
  

и это работает так

 julia> lista=LList{Int}()
LList{Int64}(#undef)

julia> push!(lista, 1)
LList{Int64}(Nodo{Int64}(1, #undef))

julia> push!(lista, 2)
LList{Int64}(Nodo{Int64}(1, Nodo{Int64}(2, #undef)))

julia> push!(lista, 3)
LList{Int64}(Nodo{Int64}(1, Nodo{Int64}(2, Nodo{Int64}(3, #undef))))
  

Этот подход не вводит поля объединения, но делает весь код более хрупким, поскольку вам нужно переключаться между nodo.next isdefined(nodo, :next) обозначениями и .