swift数据结构:链表

swift实现链表及链表的相关特性,最后附上两道算法题

一、链表的基本操作实现

1、定义链表节点

class ListNode{
    var val : Int!
    var next : ListNode!
    
    init(_ val : Int) {
        self.val = val
        self.next = nil
    }
}

2、链表的基本操作

class List{
    var head : ListNode?
    var tail : ListNode?
    
    //尾插法
    func appendToEnd(_ val : Int){
        if tail == nil {
            tail = ListNode(val)
            head = tail
        }else{
            tail?.next = ListNode(val)
            head = tail?.next
        }
    }
    
    //头插法
    func appendToHead(_ val : Int){
        if head == nil{
            head = ListNode(val)
            tail = head
        }else{
            let tmp = ListNode(val)
            tail?.next = head
            head?.next = tmp
        }
    }
}

以上就是链表的基本操作,那么我们如何利用链表来解决问题呢?请看下面的题目

二、算法

1、Dummy节点和尾插法

什么是Dummy节点?

答: dummy节点的作用就是一个虚拟的头前节点,由于我们不知道需要返回的新链表的头节点是哪一个,可能是原链表的第一个/中间/最后一个/不存在nil,而dummy涵盖了所有的情况,所以可以用dummy.next 方便返回最终需要的头节点

 

题目描述:给出一个链表和一个值x,要求将链表中所有小于x的值放到左边,所有大于x的值放到右边,并且原链表的节点顺序不能变

例如:1->5->3->2->4->2,给定 x=3 ,则返回为 1->2->2->5->3->4

思路:对于这道题目,我们需要先处理左边 即小于x的节点, 再处理右边 即大于x的节点,最后再将左右两边连起来

那么问题来了,我们如何处理左边?如何处理右边?处理完成后如何链接?

1)首先,将题目简化:

给出一个链表和一个值x,要求只保留链表中所有小于x的值,原链表的节点顺序不能变

例如:1->5->3->2->4->2,给定 x=3 ,则返回为 1->2->2

2)题目1)的实现:采用 尾插法 ,遍历链表,将小于x的节点接入新的链表即可

func getLeftList(_ head : ListNode?, _ x : Int)->ListNode? {
        let dummy : ListNode = ListNode(0)
        var pre = dummy, node = head
        
        while node != nil {
            if node!.val < x {
                pre.next = node
                pre = node!
            }
            node = node!.next
        }
        
        //防止构成环
        pre.next = nil
        
        return dummy.next
    }

3)右边用同样的方法处理,最后只需要让左边的的尾节点 指向 右边的头节点即可

具体实现

func partition(_ head : ListNode?, _ x : Int)->ListNode? {
        let prevDummy : ListNode = ListNode(0), postDummy = ListNode(0)
        var prev = prevDummy, post = postDummy
        
        var node = head
        
        while node != nil {
            if node!.val < x {
                prev.next = node
                prev = node!
            }else{
                post.next = node
                post = node!
            }
            node = node!.next
        }
        
        //防止构成环
        post.next = nil
        
        //拼接左右链表
        prev.next = postDummy.next
        
        return prevDummy.next
    }
    

4)验证

        let one = ListNode(1)
        let two = ListNode(5)
        let three = ListNode(3)
        let four = ListNode(2)
        let five = ListNode(4)
        let six = ListNode(2)
        
        one.next = two
        two.next = three
        three.next = four
        four.next = five
        five.next = six
        
        let result = self.partition(one, 3)
        var dummy = result
        while dummy != nil {
            print("node val: \(dummy?.val)")
            dummy = dummy?.next
        }

结果为:

2、快行指针

什么是快行指针?

答:就是两个指针访问链表,一个在前,一个在后,或者一个移动块,一个移动慢

 

题目一描述:如何检测一个链表中是否有环?

例如:

         

思路:用两个指针同时访问链表,其中一个指针的速度是另一个指针的2倍,如果她们变成相等的了,那么该链表就有环

 
    func hasCycle(_ head : ListNode?)->Bool{
        var slow = head, fast = head
        
        while fast != nil && fast?.next != nil {
            slow = slow?.next
            fast = fast?.next.next
            
            //判断节点是否一致时,需要节点遵守Equatable协议
            if slow==fast {
                return true
            }
        }
        return false
    }



extension ListNode : Equatable{
    static func == (lhs: ListNode, rhs: ListNode) -> Bool {
        //判断链那个节点的值以及节点的下一个节点值是否一致,一致则节点相等,反之不相等
        let result = (lhs.val==rhs.val)&&(lhs.next.val==rhs.next.val)
        return result
    }
    

}

验证:

        let one = ListNode(1)
        let two = ListNode(5)
        let three = ListNode(3)
        let four = ListNode(2)
        let five = ListNode(4)
        let six = ListNode(2)
        
        one.next = two
        two.next = three
        three.next = four
        four.next = five
        five.next = six
        
        let result = self.hasCycle(one)
        print("result : \(result)")


result结果为: false


在上面的链表基础上加上,构成环
        six.next = three
result结果为: true   

 

题目二描述:删除链表中倒数第n个节点(快行指针一前一后的例子)

例如:1->2->3->4->5,n=2,返回为 1->2->3->5

思路:两个指针的移动速度相同,但在一开始,第一个指针(在指向头节点之前)就落后第二个指针n个节点,接着,两个指针同时移动,当第二个指针移动到尾节点时,第一个节点的下一个节点就是我们要删除的节点

具体实现:

func removeNthFromEnd(_ head : ListNode?, _ n : Int)->ListNode?{
        guard let head = head else {
            return nil
        }
        
        let dummy = ListNode(0)
        dummy.next = head
        var prev : ListNode? = dummy
        var post : ListNode? = dummy
        
        //设置后一个节点的初始位置,与前一个节点相差n个节点
        for _ in 0..<n {
            if post == nil {
                break
            }
            post = post?.next
        }
        
        //同时移动前后节点
        while post != nil && post?.next != nil {
            prev = prev?.next
            post = post?.next
        }
        
        //删除节点
        prev?.next = prev?.next.next
        
        //返回删除节点后链表头节点
        return dummy.next
    }

验证

        let one = ListNode(1)
        let two = ListNode(2)
        let three = ListNode(3)
        let four = ListNode(4)
        let five = ListNode(5)
        
        one.next = two
        two.next = three
        three.next = four
        four.next = five
        
        let result = self.removeNthFromEnd(one, 2)
        var dummy = result
        while dummy != nil {
            print("node val : \(dummy?.val)")
            dummy = dummy?.next
        }

用swift处理链表问题需要注意的细节:

1)一定要注意头节点可能就是nil,所以给定链表后,要看清楚head是不是 可选类型 optional,然后判断是不是要处理这种边界条件

2)注意每个节点的next可能是nil,如果不为nil,则用“!”修饰变量,在赋值的时候,也要注意“!”将optional 节点传给非optional 节点的情况

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swift 是一种面向对象的编程语言,可以用于实现各种数据结构和算法。下面是一些常用的数据结构和算法的 Swift 实现: 1. 数组(Array):Swift 的数组可以存储同一类型的元素,并且支持动态扩展和收缩。例如: ``` var array = [1, 2, 3, 4, 5] array.append(6) array.removeLast() ``` 2. 链表(Linked List):链表是一种动态数据结构,可以在运行时添加或删除元素。例如: ``` class ListNode { var val: Int var next: ListNode? init(_ val: Int) { self.val = val self.next = nil } } var head = ListNode(1) head.next = ListNode(2) head.next?.next = ListNode(3) ``` 3. 栈(Stack):栈是一种后进先出(LIFO)的数据结构Swift 的数组可以很方便地实现栈。例如: ``` var stack = [Int]() stack.append(1) stack.append(2) stack.popLast() ``` 4. 队列(Queue):队列是一种先进先出(FIFO)的数据结构Swift 的数组也可以实现队列,但效率不高。可以使用双端队列(Deque)来实现。例如: ``` struct Deque<T> { private var left = [T]() private var right = [T]() mutating func enqueue(_ element: T) { right.append(element) } mutating func dequeue() -> T? { if left.isEmpty { left = right.reversed() right.removeAll() } return left.popLast() } } var queue = Deque<Int>() queue.enqueue(1) queue.enqueue(2) queue.dequeue() ``` 5. 哈希表(Hash Table):哈希表是一种键值对存储的数据结构Swift 的字典(Dictionary)就是哈希表的一种实现。例如: ``` var dict = [String: Int]() dict["one"] = 1 dict["two"] = 2 dict["one"] ``` 6. 排序算法:Swift 提供了快速排序(Quick Sort)、归并排序(Merge Sort)、堆排序(Heap Sort)等常见的排序算法的实现。例如: ``` func quickSort<T: Comparable>(_ array: [T]) -> [T] { guard array.count > 1 else { return array } let pivot = array[array.count / 2] let less = array.filter { $0 < pivot } let equal = array.filter { $0 == pivot } let greater = array.filter { $0 > pivot } return quickSort(less) + equal + quickSort(greater) } let array = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] quickSort(array) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值