微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

swift 中我的 LinkedList 中的删除函数中的错误

如何解决swift 中我的 LinkedList 中的删除函数中的错误

我正在尝试在 swift 中实现一个像 Java 中的通用链表 API。这可能以数百种方式完成,但我的问题不是如何做到这一点,而是关于我的逻辑的一部分有什么问题删除索引为零的项目。我知道,有其他方法可以实现我想要的,我做到了,但我需要了解特定逻辑中的缺陷。请看一下。

我现在有以下功能

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

仅当我尝试从列表的开头(索引 = 0)删除项目时,我的逻辑缺陷才出现在 remove(index:) 方法中。我的逻辑是,如果列表中的项目超过 1 个(list.size>0),则将 head 的 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)
    }
}

测试代码如 -

let list = LinkedList<Int>()
for i in 0...5{
   list.add(i)
}
list.print()
let index = 0
list.removeAt(index: index)
print("After removing..")
list.print()

输出

1
2
3
4
5
After removing..
1
2
3
4
5

谁能指出我的错。

解决方法

列表的头部成为下一项,如果有的话。如果下一项为 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

在删除索引 0 时,我们将 last 设置为 head,而 secondLast 也设置为 head

last -> 100[ |next -> 200]
secondLast -> 100[ |next -> 200]

那我们说

if let next = last.next { last = next } return

现在最后指向 200:

last -> 200[ |next -> 300]

但是列表的头部没有改变

list's head -> 100[ |next -> 200]
secondLast -> 100[ |next -> 200]

Last 超出范围,当我们返回时,列表结构(在堆中)没有发生任何变化。

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

    while count < index{
        guard let next = last.next else{
            return
        }
        secondLast = last
        last = next
        count = count + 1
    }
    secondLast.next = last.next

我们遍历操作 secondLast 和 last 的循环,然后在某个时刻到达线

secondLast.next = ...

那么我们实际上分配给对象,我们改变堆中的对象,它是下一个指针,我们从类似的东西出发:

secondLast -> 100[ |next -> 200]

secondLast -> 100[ |next -> 300]

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

,

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

现在,当我从 head(index>0) 开始迭代时,最后一个与 head 相同,并且每次迭代时 last 都会向前移动到 next 节点。我随时更改任何节点的下一个指针,该节点的下一个指针已成功更新。这里的起始节点与头节点相同,头节点指向相同的地址。因此,对于列表的迭代,无论我是从 head 还是 last 开始都没有关系,链式链接是相同的。这里 head 和 last 一开始是一样的。但是对于 index = 0,作为列表的头部,本身需要更改,使 last 指向不同的节点将不起作用,因为列表知道头部并且头部没有更新。 因此,真正的原因是列表不知道节点与一个异常之间如何相互关联,即头。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。