swift中我的LinkedList中的remove函数存在错误

swift中我的LinkedList中的remove函数存在错误,swift,data-structures,reference,singly-linked-list,Swift,Data Structures,Reference,Singly Linked List,我正试图在swift中实现一个通用的linkedList API,就像Java中的一样。这可能有数百种方法,但我的问题不是如何实现,而是在删除索引为零的项时,我的逻辑的一部分出了什么问题。我知道,有其他方法可以实现我想要的,我做到了,但我需要理解特定逻辑中的缺陷。请看一看 我现在有以下功能 var size : Int { get } //give the size of the list func add(_ value: Item) //add items to the list func

我正试图在swift中实现一个通用的linkedList API,就像Java中的一样。这可能有数百种方法,但我的问题不是如何实现,而是在删除索引为零的项时,我的逻辑的一部分出了什么问题。我知道,有其他方法可以实现我想要的,我做到了,但我需要理解特定逻辑中的缺陷。请看一看

我现在有以下功能

var size : Int { get } //give the size of the list
func add(_ value: Item) //add items to the list
func removeAt(index: Int) // removes the item from the specified index
func print() //prints the list
我的逻辑缺陷存在于
remove(index:)
方法中,仅当我尝试从列表的开头(index=0)删除一个项时。我的逻辑是,如果列表中有多个项目(list.size>0),则将头部的
next
节点设置为
head

以下是完整的实现-

import Foundation

class Node<Item>{
    var value: Item
    var next: Node?
    
    init(value: Item) {
        self.value = value
        self.next = nil
    }
}

class LinkedList<Item> {
    var head: Node<Item>?
    
    public init(){
        self.head = nil
    }
    
    public init(_ value: Item){
        self.head = Node(value: value)
    }
    
    private func isEmpty()->Bool{
        if head == nil{
            return true
        }
        return false
    }
    
    var size : Int {
        guard var current = head else{
            return 0
        }
        var count = 1
        while current.next != nil {
            guard let next = current.next else {
                return count
            }
            count = count + 1
            current = next
        }
        return count
    }
    
    func add(_ value: Item){
        let node = Node(value: value)
        if isEmpty(){
            head = node
            return
        }
        guard let head = head else {
            return
        }
        var currentNode = head
        while currentNode.next != nil {
            guard let nextNode = currentNode.next else {
                break
            }
            currentNode = nextNode
        }
        currentNode.next = node
    }
    
    func removeAt(index: Int) {
        if isEmpty() || index >= self.size{
            return
        }
        guard var last = head, var secondLast = head else{
            return
        }
        // when index is zero and either the list has only one item or it has multiple items
        if index == 0{ //here is the bug
            if let next = last.next{
                last = next
            }else{
                head = nil
            }
            return
        }
        var count = 0
        while count < index{
            guard let next = last.next else{
                return
            }
            secondLast = last
            last = next
            count = count + 1
        }
        secondLast.next = last.next
    }
    
    func print(){
        guard var current = head else {
            return
        }
        if current.next == nil{ //if list contains only head
            Swift.print(current.value)
            return
        }
        while current.next != nil{
            Swift.print(current.value)
            guard let next = current.next else {
                return
            }
            current = next
        }
        Swift.print(current.value)
    }
}

谁能指出我的错误吗。

如果有错误,列表的标题将成为下一项。如果下一项为nil,则列表的标题也为nil,如下所示:

    if index == 0 { //here is the bug
        head = head?.next
        return
    }
此代码:

if let next = last.next{
    last = next
}else{
    head = nil
}
在第一个分支中,返回时不更改“head”,因此列表的head保持不变

假设头部在地址100处 列表中的第二项是地址200

let list = LinkedList<Int>()
list's head -> 100
然后我们说

if let next = last.next { last = next } return
现在最后一点是200:

last -> 200[ |next -> 300]
但名单的标题并没有改变

list's head -> 100[ |next -> 200]
secondLast -> 100[ |next -> 200]
最后一个超出范围,当我们返回时,列表结构(在堆中)没有发生任何更改

在工作分支中(其中索引>0):

然后我们实际分配给对象,我们在堆中对对象进行变异,它是下一个指针,我们从如下内容开始:

secondLast -> 100[ |next -> 200]

secondLast -> 100[ |next -> 300]

所以现在列表本身已经改变了,在堆中,地址为100的对象有一个指向某个对象的下一个指针,例如地址为300的对象。

首先,我非常感谢@Shadowrun投入的时间和精力。但是,当我迭代列表并在
列表
之间删除时,解释仍然缺少代码工作的原因。 原因是列表本身只包含一个指针,head指向内存中的地址。确保
last
节点指向相同的地址,但当我尝试在
last
的帮助下更新
头部(索引=0)时,
last
指向不同的地址,这意味着它一离开作用域就偏离头部。虽然
list
不知道发生了什么变化,但list仍然保持与以前相同的指向地址的指针

现在,当我从head(index>0)迭代时,最后一个与
head
相同,每次迭代
last
都会向前移动到
next
节点。我随时更改任何节点的下一个指针,该节点的下一个指针将成功更新。在这里,起始节点与最后一个节点的头部相同,头部指向相同的地址。所以,对于列表上的迭代,不管我是从head开始还是从last开始,链链接都是一样的。这里头和尾在开头是一样的。但对于index=0,作为列表的头,它本身需要更改,使最后一个指向不同的节点将不起作用,因为列表知道头,而头不会更新。 所以,真正的原因是,列表没有线索表明节点的是如何相互关联的,只有一个例外,那就是头部


这与分配对象或其他任何内容无关。这是关于只指向一个节点的列表,即
head

我知道修复方法,您提到过,但我需要知道为什么我的逻辑有缺陷。根据引用类型的基本规则,当我将head指定给last时,last和head都指向同一个引用。因此,如果我更改last,last和head都应该更改。last=head,但您没有更改last(这会更改head),您将它设置为指向其他内容,当您说last=next时,您需要修改的是LinkedList本身上的self.head。将last设置为与self.head当前所在的对象相同的对象,然后将last设置为与其他对象相等,因此现在self.head和last指向两个不同的对象。self.head的值永远不会更改为其他对象。两个变量a和b指向某个对象O。您可以使用a或b修改O。但您不希望使用别名修改对象本身。您需要更改a指向哪个对象,而不是更改a指向的对象。如果是这种逻辑,下面的代码也不应该工作。我正在改变它指向的地方。如果在下面的代码中,通过迭代每个节点并将last.next分配给second.last make secondLast来跳过中间的一个节点,那么为什么将另一个节点分配给last将不起作用。
last -> 200[ |next -> 300]
list's head -> 100[ |next -> 200]
secondLast -> 100[ |next -> 200]
    while count < index{
        guard let next = last.next else{
            return
        }
        secondLast = last
        last = next
        count = count + 1
    }
    secondLast.next = last.next
secondLast.next = ...
secondLast -> 100[ |next -> 200]

secondLast -> 100[ |next -> 300]