【问题标题】:How to implement doubly linked list in swift?如何在swift中实现双向链表?
【发布时间】:2019-11-23 01:20:43
【问题描述】:

如何在 Swift 中实现具有插入和删除等所有操作的双向链表?

我知道如何实现单链表,但我找不到使它成为双链表的方法。我是编码初学者。

import UIKit

struct LinkedList<Value> {

    var Head : node<Value>?
    var Tail : node<Value>?

    var isEmpty : Bool {
        return Head == nil
    }

    // to add at the beginning of the list
    mutating func push(_ value : Value) {
        Head = node(value: value, nextNode: Head)
        if Tail == nil {
            Tail = Head
        }
    }

    // to add at the end of the list
    mutating func append(_ value : Value) {
        guard !isEmpty else {
            push(value)
            return
        }

        let newNode = node(value: value)
        Tail?.nextNode = newNode
        Tail = newNode
    }

    //to find the node at particular index
    func findNode(at index: Int) -> node<Value>? {
         var currentIndex = 0
         var currentNode = Head
        while(currentNode != nil && currentIndex < index) {
             currentNode = currentNode?.nextNode
            currentIndex += 1
        }
        return currentNode
    }

    // to insert at a particular location

    func insert(_ value : Value, afterNode : node<Value>) {
        afterNode.nextNode = node(value: value, nextNode: afterNode.nextNode)
    }

    mutating func pop() -> Value? {

        defer {
            Head = Head?.nextNode
            if isEmpty {
                Head = nil
            }
        }

        return Head?.value
    }


    mutating func removeLast() -> Value? {

        guard let head = Head else {
            return nil
        }
        guard head.nextNode != nil else {
            return pop()
        }

        var previous = head
        var current = head

        while let next = current.nextNode {
            previous = current
            current = next
        }

        previous.nextNode = nil
        Tail = previous
        return current.value

    }

    mutating func remove(after node : node<Value>?) -> Value? {

        defer {
            if node === Tail {
                Tail = node
            }
            node?.nextNode = node?.nextNode?.nextNode
        }
        return node?.nextNode?.value
    }
}

extension LinkedList : CustomStringConvertible {
    var description: String {

        guard let linkedListHead = Head else {
            return "Empty List"
        }
        return String(describing: linkedListHead)
    }


}

class node<Value> {

    var value : Value
    var nextNode : node?

    init(value : Value , nextNode : node? = nil) {

        self.value = value
        self.nextNode = nextNode

    }

}


extension node : CustomStringConvertible {
    var description: String {
        guard let nextValue = nextNode else { return "\(value)" }

        return "\(value) -> " + String(describing: nextValue) + " "
    }


}

var listOfIntegers = LinkedList<Int>()
var listOfStrings = LinkedList<String>()

listOfIntegers.push(1)
listOfIntegers.push(3)
listOfIntegers.push(4)
listOfIntegers.append(6)
let nodeInfo = listOfIntegers.findNode(at: 1)!
listOfIntegers.insert(8, afterNode: nodeInfo)
print(listOfIntegers)
listOfStrings.push("hello")
listOfStrings.push("Sardar Ji!")
print(listOfStrings)
let index = 3
let node2 = listOfIntegers.findNode(at: index - 1)
listOfIntegers.remove(after: node2)
print(listOfIntegers)

我想以同样的方式实现双向链表,输出应该是这样的:

node1 <-> node2 <-> node3

【问题讨论】:

  • 您的node 类应以大写字母Node 开头。首先要做的是将prevNode 属性添加到您的Node 类。然后在插入/删除时修复两个方向的指针。
  • 在纸上用箭头显示上一个和下一个指针真的很有帮助。
  • headtail,属性应该以小写字母开头。

标签: swift linked-list doubly-linked-list


【解决方案1】:
//here is the full implementaion of doubly-linked-list in swift. updates will be appreciated.

import Foundation

struct DoublyLinkedList<DataItem> {

    fileprivate var head : Node<DataItem>?
    fileprivate var tail : Node<DataItem>?
    var isEmpty : Bool {
        return head == nil
    }

    //to add at the beginning
    mutating func InsertAtBeginning(_ dataItem : DataItem) {
        let node = Node(dataItem: dataItem, nextNode: head, previousNode: nil)
        head?.previousNode = node
        head = node
        if tail == nil {
            tail = head
        }
    }

    //to add at the end
    mutating func insertAtEnd(_ dataItem : DataItem) {
        guard !isEmpty else {
            InsertAtBeginning(dataItem)
            return
        }

        let newNode = Node(dataItem: dataItem, nextNode: nil, previousNode: tail)
        tail?.nextNode = newNode
        //newNode.previousNode = tail
        tail = newNode

    }

    //to insert at particular node
    func insertParticularly(_ dataItem : DataItem , afterNode : Node<DataItem>) {
        let node = Node(dataItem: dataItem)
        afterNode.nextNode?.previousNode = node
        node.nextNode = afterNode.nextNode
        afterNode.nextNode = node
        node.previousNode = afterNode


    }

    //to find a node at particular index
    func findNode(at index : Int) -> Node<DataItem>? {
        var currentIndex = 0
        var currentNode =  head
        while currentNode != nil && currentIndex < index {
            currentNode = currentNode?.nextNode
            currentIndex += 1
        }
        return currentNode
    }

    //MARK:- remove functionality

    //remove the first element
    mutating func removeFirst() -> DataItem? {

        defer {
            head = head?.nextNode
            if isEmpty {
                head = nil
            }
        }

        return head?.dataItem
    }

    // remove the last element
    mutating func removeLast() -> DataItem? {


        guard let headValue = head else {
            return nil
        }

        guard headValue.nextNode != nil else {
            return removeFirst()
        }

        var previous = headValue
        var current = headValue

        while let next = current.nextNode {
            previous = current
            current = next
        }

        previous.nextNode = nil
        tail = previous
        return current.dataItem

    }

    // remove from a specific location
    mutating func removeAt(at node : Node<DataItem>?) -> DataItem? {
        defer {
            if node === tail {
                removeLast()
            }
            node?.previousNode?.nextNode = node?.nextNode
            node?.nextNode?.previousNode = node?.previousNode
        }
        return node?.nextNode?.dataItem
    }

}

extension DoublyLinkedList : CustomStringConvertible {

    var description : String {
        guard let doublyLinkedListHead = head else { return "UnderFlow"}
        //return String(describing: doublyLinkedListHead)
        return doublyLinkedListHead.linkedDescription
    }

}

class Node<DataItem> {
    var dataItem : DataItem
    var nextNode : Node?
    var previousNode : Node?



    init(dataItem : DataItem , nextNode : Node? = nil , previousNode : Node? = nil) {
        self.dataItem = dataItem
        self.nextNode = nextNode
        self.previousNode = previousNode
    }
}

extension Node : CustomStringConvertible {

    var description: String {
        return ((previousNode == nil) ? "nil" : "\(previousNode!.dataItem)") +
                " <-> \(dataItem) <-> " +
            ((nextNode == nil) ? "nil" : "\(nextNode!.dataItem)")
    }
        var linkedDescription: String {
            return "\(dataItem)" + ((nextNode == nil) ? "" : " <-> \(nextNode!.linkedDescription)")

        }

}

var list = DoublyLinkedList<Int>()
list.InsertAtBeginning(4)
list.insertAtEnd(5)
list.insertAtEnd(4)
list.insertAtEnd(7)
list.insertAtEnd(2)
list.insertAtEnd(0)

list.description
let node1 = list.findNode(at: 3)
node1?.previousNode
list.head

【讨论】:

    【解决方案2】:

    从根本上说,您的问题是 LinkedList 中有头尾指针,但 node 只有 nextNode 指针。如果node 是表示列表中每个项目的结构,并且如果您希望能够以任一方向遍历列表,那么每个项目都需要指向下一个项目和前一个项目的链接。这就是为什么他们称它为“双向链表”。

    1. previousNode 指针添加到您的node 结构。
    2. 查找代码中修改nextNode 指针的每个位置,并更改代码以同时维护previousNode 指针。

    【讨论】:

      猜你喜欢
      • 2012-05-10
      • 1970-01-01
      • 2021-11-18
      • 2011-06-03
      • 2015-05-16
      • 1970-01-01
      • 2018-04-14
      • 2018-03-14
      相关资源
      最近更新 更多