Swift链表

时间:2020-02-23 14:44:02  来源:igfitidea点击:

在本教程中,我们将使用Swift讨论和实现链接列表数据结构。

什么是LinkedList?

LinkedList是一种数据结构,可以线性/顺序保存数据。

通常,我们将LinkedList的每个元素称为节点。

因此,每个节点都由值和对下一个元素的引用组成。

下图说明了一个节点。

LinkedList只是节点列表,每个节点其中存储下一个节点的引用。

第一节点通常称为HEAD。
当最后一个节点的NEXT为Nil时,LinkedList完成。

双链表会存储其上一个节点和下一个节点的引用。

在以下部分中,我们将创建Node结构并在LinkedList上执行各种操作,例如:

  • 追加新元素
  • 链表的大小
  • 在某个位置插入元素
  • 删除元素
  • 向前和向后打印LinkedList
  • 从特定位置检索节点

打开您的Xcode Playground,让Swift来吧!

创建一个Swift LinkedList节点

我们可以创建一个通用类型的节点,如下所示:

public class SNode<T> {
  var value: T
  var next: SNode<T>?
  
  init(value: T) {
      self.value = value
  }
}

SNode代表LinkedList的Node的实例。

让我们创建一个类" SingleLinkedList <T>",其中创建并修改我们的LinkedList

class SingleLinkedList<T> {
  
  var head: SNode<T>? //head is nil when list is empty
  
  public var isEmpty: Bool {
      return head == nil
  }
  
  public var first: SNode<T>? {
      return head
  }

isEmpty是一个属性,用于检查LinkedList是否为空。
如果头为零,则LinkedList将为空。

在Swift LinkedList中追加元素

在上面的类中添加以下append函数。

public func append(value: T) {
      let newNode = SNode(value: value)
      if var h = head {
          while h.next != nil {
              h = h.next!
          }
          h.next = newNode
          
      } else {
          head = newNode
      }
  }

append函数将一个新的Node添加到列表的末尾。
为此,我们使用名为h的标头的临时Node引用遍历LinkedList的末尾。

当h的下一个引用为nil时,表示我们位于LinkedList的末尾。
我们在这里通过将最后一个节点的下一个设置为newNode。

在某个位置插入元素

要在某个位置插入元素,我们需要:将先前的Node NEXT引用设置为新元素。
将新元素的NEXT设置为当时存在的当前元素。

将以下函数插入添加到上面的LinkedList类中。

func insert(data : T, at position : Int) {
      let newNode = SNode(value: data)
      
      if (position == 0) {
          newNode.next = head
          head = newNode
      }
      else {
          var previous = head
          var current = head
          for _ in 0..<position {
              previous = current
              current = current?.next
          }
          
          newNode.next = previous?.next
          previous?.next = newNode
      }
  }

从Swift LinkedList删除节点

要删除一个节点,我们需要将前一个节点的引用设置为要删除的节点的NEXT。

在上面的类中添加以下函数。

func deleteNode(at position: Int)
  {
      if head == nil{
      return
      }
      var temp = head
      
      if (position == 0)
      {
          head = temp?.next;   //Change head
          return
      }
  
      for _ in 0..<position-1 where temp != nil {
          temp = temp?.next;
      }

      if temp == nil || temp?.next == nil{
         return
      }

      let nextToNextNode = temp?.next?.next
      
      temp?.next = nextToNextNode
  }

打印元素

要打印元素,我们需要遍历LinkedList直到到达最后一个元素并一路打印这些元素。

要以相反的顺序打印元素,我们使用递归函数!

func printList() {
      var current: SNode? = head
      //assign the next instance
      while (current != nil) {
          print("LL item is: \(current?.value as? Int ?? 0)")
          current = current?.next
      }
  }
  
  
  func printReverseRecursive(node: SNode<T>?) {
  if node == nil{
  return
  }
  printReverseRecursive(node: node?.next)
  print("LL item is: \(node?.value as? Int ?? 0)")
  }
  
  func printReverse() {
      printReverseRecursive(node: first)
      
  }

将以上所有操作汇总到我们的类中将使我们的类看起来像这样:

class SingleLinkedList<T> {
  
  var head: SNode<T>? //head is nil when list is empty
  
  public var isEmpty: Bool {
      return head == nil
  }
  
  public var first: SNode<T>? {
      return head
  }
  
  public func append(value: T) {
      let newNode = SNode(value: value)
      if var h = head {
          while h.next != nil {
              h = h.next!
          }
          h.next = newNode
          
      } else {
          head = newNode
      }
  }
  
  func insert(data : T, at position : Int) {
      let newNode = SNode(value: data)
      
      if (position == 0) {
          newNode.next = head
          head = newNode
      }
      else {
          var previous = head
          var current = head
          for _ in 0..<position {
              previous = current
              current = current?.next
          }
          
          newNode.next = previous?.next
          previous?.next = newNode
      }
  }
  
  func deleteNode(at position: Int)
  {
      if head == nil{
      return
      }
      var temp = head
      
      if (position == 0)
      {
          head = temp?.next
          return
      }
  
      for _ in 0..<position-1 where temp != nil {
          temp = temp?.next
      }

      if temp == nil || temp?.next == nil{
         return
      }

      let nextToNextNode = temp?.next?.next
      
      temp?.next = nextToNextNode
  }
  
  func printList() {
      var current: SNode? = head
      //assign the next instance
      while (current != nil) {
          print("LL item is: \(current?.value as? Int ?? 0)")
          current = current?.next
      }
  }
  
  
  func printReverseRecursive(node: SNode<T>?) {
  if node == nil{
  return
  }
  printReverseRecursive(node: node?.next)
  print("LL item is: \(node?.value as? Int ?? 0)")
  }
  
  func printReverse() {
      printReverseRecursive(node: first)
      
  }
}

让我们从LinkedList中添加,插入或者删除元素。

let ll = SingleLinkedList<Int>()
ll.append(value: 1)
ll.append(value: 2)
ll.append(value: 4)
ll.insert(data: 5, at: 0)
ll.insert(data: 10, at: 1)
ll.printList()
ll.deleteNode(at: 0)
print("Printing Reverse:")
ll.printReverse()

双链表

让我们为双重链接列表创建一个节点。

public class DNode<T> {
var value: T
var next: DNode<T>?
weak var previous: DNode<T>?

init(value: T) {
  self.value = value
}
}

为了防止出现记忆周期,我们将先前的参考设置为弱。

public class DoublyLinkedList<T> {
var head: DNode<T>?
private var tail: DNode<T>?

public var isEmpty: Bool {
  return head == nil
}

//first
public var first: DNode<T>? {
  return head
}

//last
public var last: DNode<T>? {
  return tail
}
//Append node to LinkedList
public func append(value: T) {
  let newNode = DNode(value: value)
  if let tailNode = tail {
    newNode.previous = tailNode
    tailNode.next = newNode
  } else {
    head = newNode
  }
  tail = newNode
}
  
  func insert(node: DNode<T>, at index: Int) {
      if index == 0,
          tail == nil {
          head = node
          tail = node
      } else {
          guard let nodeAtIndex = nodeAt(index: index) else {
              print("Index out of bounds.")
              return
          }
          
          if nodeAtIndex.previous == nil {
              head = node
          }
          
          node.previous = nodeAtIndex.previous
          nodeAtIndex.previous?.next = node
      
          node.next = nodeAtIndex
          nodeAtIndex.previous = node
      }
  }

//Find Node at Index
public func nodeAt(index: Int) -> DNode<T>? {
  if index >= 0 {
    var node = head
    var i = index
    while node != nil {
      if i == 0 { return node }
      i -= 1
      node = node!.next
    }
  }
  return nil
}
  
public func removeAll() {
  head = nil
  tail = nil
}

//remove Node
public func remove(node: DNode<T>) -> T {
  let previousNode = node.previous
  let nextNode = node.next

  if let prev = previousNode {
    prev.next = nextNode
  } else {
    head = nextNode
  }
  nextNode?.previous = previousNode

  if nextNode == nil {
    tail = previousNode
  }

  node.previous = nil
  node.next = nil
  
  return node.value
}
  
  var count: Int {
      if (head?.value == nil) {
          return 0
      }
      else {
          var current: DNode? = head
          var x: Int = 1
          
          //cycle through the list of items
          while ((current?.next) != nil) {
              current = current?.next!
              x = x + 1
          }
          return x
      }
  }
  
  func printReverse() {
      var current: DNode? = tail;
      //assign the next instance
      while (current != nil) {
          print("DLL item is: \(current?.value as? String ?? "NA")")
          current = current?.previous
      }
  }
  
  func printForward() {
      var current: DNode? = head
      //assign the next instance
      while (current != nil) {
          print("DLL item is: \(current?.value as? String ?? "NA")")
          current = current?.next
      }
  }
  //remove from index
  func remove(at index: Int) {
      var toDeleteNode = nodeAt(index: index)
      guard toDeleteNode != nil else {
          print("Index out of bounds.")
          return
      }
      
      let previousNode = toDeleteNode?.previous
      let nextNode = toDeleteNode?.next
      
      if previousNode == nil {
          head = nextNode
      }
      
      if toDeleteNode?.next == nil {
          tail = previousNode
      }
      
      previousNode?.next = nextNode
      nextNode?.previous = previousNode
      
      toDeleteNode = nil
  }
}

在双向链接列表中,我们会同时处理上一个和下一个参考。

let dd = DoublyLinkedList<String>()
dd.append(value: "Harry Potter")
dd.append(value: "Ron")
dd.append(value: "Hermione")
dd.append(value: "Hagrid")
dd.append(value: "Draco")
dd.append(value: "Snape")

//Run the following
print(dd.count)
dd.printReverse()
dd.remove(at: 1)
var dNode = DNode(value: "Harry Potter")
dd.remove(node: dNode)
print(dd.nodeAt(index: 4))
print(dd.nodeAt(index: 10))
dd.insert(node: dNode, at: 4)
dd.printForward()