单向循环链表的特点:最后一个数据元素的指针域,指向首元结点
image.png

  • 设计一个循环链表时,也可以增加头结点降低逻辑复杂度

1. 创建

循环链表在创建元素时分为两种情况:

  • 当循环链表为空表时,第一次创建元素

  • 当循环链表非空表时,创建更多元素

【情况一】当循环链表为空表时,只存在一个指针。创建第一个元素时,创建新结点并赋值,将指针域指向自身
image.png

【情况二】当循环链表非空表时,假设采用后插法,需要先找到链表的结尾位置,然后创建新结点并赋值,将尾结点的指针域指向新结点,将新结点的指针域指向首元结点
image.png

1.1 通过循环找到尾结点

  1. import Foundation
  2. public struct CircularLinkedList<Element>{
  3. fileprivate class Node<T>: Equatable {
  4. static func == (lhs: CircularLinkedList<Element>.Node<T>, rhs: CircularLinkedList<Element>.Node<T>) -> Bool {
  5. let obj1 = Unmanaged<AnyObject>.passUnretained(lhs).toOpaque();
  6. let obj2 = Unmanaged<AnyObject>.passUnretained(rhs).toOpaque();
  7. return obj1 == obj2;
  8. }
  9. var next : Node<T>?;
  10. var data : T?;
  11. init(data : T){
  12. self.data = data;
  13. self.next = nil;
  14. }
  15. deinit {
  16. print("值为\(data!)的Node释放");
  17. }
  18. }
  19. fileprivate var _head : Node<Element>? = nil;
  20. private var _length : Int = 0;
  21. func length() -> Int {
  22. return _length;
  23. }
  24. mutating func pushTail(element : Element) -> Int{
  25. let node = Node<Element>(data: element);
  26. if(_head == nil){
  27. _head = node;
  28. }
  29. else{
  30. var lastNode = _head;
  31. while(lastNode?.next != _head){
  32. lastNode = lastNode?.next;
  33. }
  34. lastNode?.next = node;
  35. }
  36. node.next = _head;
  37. _length += 1;
  38. return OK;
  39. }
  40. }

1.2 使用指针记录尾结点

import Foundation

public struct CircularLinkedList<Element>{

    fileprivate class Node<T>: Equatable {

        var next : Node<T>?;
        var data : T?;

        init(data : T){
            self.data = data;
            self.next = nil;
        }

        deinit {
            print("值为\(data!)的Node释放");
        }
    }

    fileprivate var _head : Node<Element>? = nil;
    fileprivate var _r : Node<Element>? = nil;
    private var _length : Int = 0;

    func length() -> Int {
        return _length;
    }

    mutating func pushTail(element : Element) -> Int{

        let node = Node<Element>(data: element);

        if(_head == nil){
            _head = node;
        }
        else{
            _r?.next = node;
        }

        node.next = _head;
        _r = node;

        _length += 1;

        return OK;
    }
}

2. 插入

循环链表在插入元素时分为两种情况:

  • 插入的位置是首元结点

  • 插入到其他位置

【情况一】插入的位置是首元结点
image.png

  • 判断插入位置是否在首元结点上

  • 创建新结点,并赋值新结点

  • 新结点指针域指向之前的首元结点,L指针指向新结点,尾结点的指针域指向新结点

【情况二】插入到其他位置
image.png

  • 创建新结点,并赋值新结点

  • 找到指定位置的前一个结点target

  • 新结点指针域指向targetnexttarget的指针域指向新结点

代码实现:

import Foundation

public struct CircularLinkedList<Element>{

    fileprivate class Node<T>: Equatable {

        static func == (lhs: CircularLinkedList<Element>.Node<T>, rhs: CircularLinkedList<Element>.Node<T>) -> Bool {
            let obj1 = Unmanaged<AnyObject>.passUnretained(lhs).toOpaque();
            let obj2 = Unmanaged<AnyObject>.passUnretained(rhs).toOpaque();

            return obj1 == obj2;
        }

        var next : Node<T>?;
        var data : T?;

        init(data : T){
            self.data = data;
            self.next = nil;
        }

        deinit {
            print("值为\(data!)的Node释放");
        }
    }

    fileprivate var _head : Node<Element>? = nil;
    private var _length : Int = 0;

    fileprivate var _r : Node<Element>? {
        get{
            var lastNode = _head;

            while(lastNode?.next != _head){
                lastNode = lastNode?.next;
            }

            return lastNode;
        }
    };

    func length() -> Int {
        return _length;
    }

    func getElem(index : Int) -> Element? {

        if(index < 0 || index >= length()){
            return nil;
        }

        let node = getNode(index: index);

        if(node == nil){
            return nil;
        }

        return node!.data;
    }

    fileprivate func getNode(index : Int) -> Node<Element>? {

        if(index < 0 || index >= length()){
            return nil;
        }

        var i = 0;
        var node = _head;

        while(node != nil && i < index){
            node = node?.next;
            i += 1;
        }

        return node;
    }

    mutating func insetr(locate : Int, element : Element) -> Int {

        let index = locate - 1;

        if(index < 0 || index > length()){
            return ERROR;
        }

        let node = Node<Element>(data: element);
        return insetrNode(index: index, node: node);
    }

    fileprivate mutating func insetrNode(index : Int, node : Node<Element>) -> Int {

        if(index == 0){

            node.next = _head;
            _r?.next = node;
            _head = node;
        }
        else{

            let ptr = getNode(index: index - 1);
            node.next = ptr?.next;
            ptr?.next = node;
        }

        _length += 1;

        return OK;
    }

    mutating func pushTail(element : Element) -> Int{

        let node = Node<Element>(data: element);

        if(_head == nil){
            _head = node;
        }
        else{
            _r?.next = node;
        }

        node.next = _head;
        _length += 1;

        return OK;
    }
}
  • 访问尾结点,_r会通过遍历方式获取

  • 不建议使用_r指针记录尾结点,因为在对尾结点插入或删除时,逻辑会变得复杂

3. 删除

循环链表在删除元素时分为两种情况:

  • 删除首元节点

  • 删除其他节点

【情况一】删除首元节点

  • 判断删除位置是否在首元结点上

  • 找到尾结点,将尾结点的指针域指向首元结点的next

  • L指针指向首元结点的next

【情况二】删除其他节点

  • 找到删除位置前一个节点

  • 将前一个节点的指针域指向该节点的nextnext

代码实现:

import Foundation

public struct CircularLinkedList<Element>{

    fileprivate class Node<T>: Equatable {

        static func == (lhs: CircularLinkedList<Element>.Node<T>, rhs: CircularLinkedList<Element>.Node<T>) -> Bool {
            let obj1 = Unmanaged<AnyObject>.passUnretained(lhs).toOpaque();
            let obj2 = Unmanaged<AnyObject>.passUnretained(rhs).toOpaque();

            return obj1 == obj2;
        }

        var next : Node<T>?;
        var data : T?;

        init(data : T){
            self.data = data;
            self.next = nil;
        }

        deinit {
            print("值为\(data!)的Node释放");
        }
    }

    fileprivate var _head : Node<Element>? = nil;
    private var _length : Int = 0;

    fileprivate var _r : Node<Element>? {
        get{
            var lastNode = _head;

            while(lastNode?.next != _head){
                lastNode = lastNode?.next;
            }

            return lastNode;
        }
    };

    func length() -> Int {
        return _length;
    }

    func getElem(index : Int) -> Element? {

        if(index < 0 || index >= length()){
            return nil;
        }

        let node = getNode(index: index);

        if(node == nil){
            return nil;
        }

        return node!.data;
    }

    fileprivate func getNode(index : Int) -> Node<Element>? {

        if(index < 0 || index >= length()){
            return nil;
        }

        var i = 0;
        var node = _head;

        while(node != nil && i < index){
            node = node?.next;
            i += 1;
        }

        return node;
    }

    mutating func insetr(locate : Int, element : Element) -> Int {

        let index = locate - 1;

        if(index < 0 || index > length()){
            return ERROR;
        }

        let node = Node<Element>(data: element);
        return insetrNode(index: index, node: node);
    }

    fileprivate mutating func insetrNode(index : Int, node : Node<Element>) -> Int {

        if(index == 0){

            node.next = _head;
            _r?.next = node;
            _head = node;
        }
        else{

            let ptr = getNode(index: index - 1);
            node.next = ptr?.next;
            ptr?.next = node;
        }

        _length += 1;

        return OK;
    }

    mutating func delete(locate : Int) -> Element? {

        let index = locate - 1;

        if(index < 0 || index >= length()){
            return nil;
        }

        var data : Element? = nil;

        if(index == 0){

            data = _head?.data;

            _r?.next = _head?.next;
            _head = _head?.next;
        }
        else{

            let node = getNode(index: index);
            data = node?.data;

            let preNode = getNode(index: index - 1);
            preNode?.next = node?.next;
        }

        _length -= 1;

        return data;
    }

    mutating func pushTail(element : Element) -> Int{

        let node = Node<Element>(data: element);

        if(_head == nil){
            _head = node;
        }
        else{
            _r?.next = node;
        }

        node.next = _head;
        _length += 1;

        return OK;
    }
}

4. 查找元素位置

在循环链表中查找元素,遍历寻找一次即可。找到元素返回位置,否则返回0

import Foundation

public struct CircularLinkedList<Element: Equatable>{

    fileprivate class Node<T>: Equatable {

        static func == (lhs: CircularLinkedList<Element>.Node<T>, rhs: CircularLinkedList<Element>.Node<T>) -> Bool {
            let obj1 = Unmanaged<AnyObject>.passUnretained(lhs).toOpaque();
            let obj2 = Unmanaged<AnyObject>.passUnretained(rhs).toOpaque();

            return obj1 == obj2;
        }

        var next : Node<T>?;
        var data : T?;

        init(data : T){
            self.data = data;
            self.next = nil;
        }

        deinit {
            print("值为\(data!)的Node释放");
        }
    }

    fileprivate var _head : Node<Element>? = nil;
    private var _length : Int = 0;

    fileprivate var _r : Node<Element>? {
        get{
            var lastNode = _head;

            while(lastNode?.next != _head){
                lastNode = lastNode?.next;
            }

            return lastNode;
        }
    };

    func length() -> Int {
        return _length;
    }

    func getElem(index : Int) -> Element? {

        if(index < 0 || index >= length()){
            return nil;
        }

        let node = getNode(index: index);

        if(node == nil){
            return nil;
        }

        return node!.data;
    }

    fileprivate func getNode(index : Int) -> Node<Element>? {

        if(index < 0 || index >= length()){
            return nil;
        }

        var i = 0;
        var node = _head;

        while(node != nil && i < index){
            node = node?.next;
            i += 1;
        }

        return node;
    }

    mutating func insetr(locate : Int, element : Element) -> Int {

        let index = locate - 1;

        if(index < 0 || index > length()){
            return ERROR;
        }

        let node = Node<Element>(data: element);
        return insetrNode(index: index, node: node);
    }

    fileprivate mutating func insetrNode(index : Int, node : Node<Element>) -> Int {

        if(index == 0){

            node.next = _head;
            _r?.next = node;
            _head = node;
        }
        else{

            let ptr = getNode(index: index - 1);
            node.next = ptr?.next;
            ptr?.next = node;
        }

        _length += 1;

        return OK;
    }

    mutating func delete(locate : Int) -> Element? {

        let index = locate - 1;

        if(index < 0 || index >= length()){
            return nil;
        }

        var data : Element? = nil;

        if(index == 0){

            data = _head?.data;

            _r?.next = _head?.next;
            _head = _head?.next;
        }
        else{

            let node = getNode(index: index);
            data = node?.data;

            let preNode = getNode(index: index - 1);
            preNode?.next = node?.next;
        }

        _length -= 1;

        return data;
    }

    mutating func pushTail(element : Element) -> Int{

        let node = Node<Element>(data: element);

        if(_head == nil){
            _head = node;
        }
        else{
            _r?.next = node;
        }

        node.next = _head;
        _length += 1;

        return OK;
    }

    func getLocate(element : Element) -> Int {

        if(length() < 1){
            return 0;
        }

        var locate = 0;
        var node = _head;

        repeat{

            locate += 1;

            if(node?.data == element){
                return locate;
            }

            node = node?.next;

        }while(node != _head)

        return 0;
    }
}

总结

循环链表在创建元素时分为两种情况:

  • 当循环链表为空表时,第一次创建元素

    • 当循环链表为空表时,只存在一个指针。创建第一个元素时,创建新结点并赋值,将指针域指向自身
  • 当循环链表非空表时,创建更多元素

    • 当循环链表非空表时,假设采用后插法,需要先找到链表的结尾位置,然后创建新结点并赋值,将尾结点的指针域指向新结点,将新结点的指针域指向首元结点

循环链表在插入元素时分为两种情况:

  • 插入的位置是首元结点

    • 判断插入位置是否在首元结点上

    • 创建新结点,并赋值新结点

    • 新结点指针域指向之前的首元结点,L指针指向新结点,尾结点的指针域指向新结点

  • 插入到其他位置

    • 创建新结点,并赋值新结点

    • 找到指定位置的前一个结点target

    • 新结点指针域指向targetnexttarget的指针域指向新结点

循环链表在删除元素时分为两种情况:

  • 删除首元节点

    • 判断删除位置是否在首元结点上

    • 找到尾结点,将尾结点的指针域指向首元结点的next

    • L指针指向首元结点的next

  • 删除其他节点

    • 找到删除位置前一个节点

    • 将前一个节点的指针域指向该节点的nextnext

循环链表中查找元素:

  • 遍历寻找一次即可。找到元素返回位置,否则返回0