zoukankan      html  css  js  c++  java
  • 用OC实现双向链表:构造链表、插入节点、删除节点、遍历节点

    一、介绍

    双向链表:每一个节点前后指针域都和它的上一个节点互相指向,尾节点的next指向空,首节点的pre指向空。

    二、使用

    注:跟单链表差不多,简单写常用的。循环链表无法形象化打印,后面也暂不实现了,但是要注意循环链表遍历时结束的标志。

    循环链表遍历结束:tailNode.next == firstNode

    双向循环链表遍历结束:tailNode.next == firstNode  && firstNode.pre == tailNode

    ***定义双向节点***

    //  DoubleLinkNode.h
    //  LinkListDemo
    //  Created by 夏远全 on 2019/9/24.
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface DoubleLinkNode : NSObject
    @property (nonatomic, assign) int data; //数据域
    @property (nonatomic,   weak, nullable) DoubleLinkNode *pre; //前驱指针域(防止循环引用)
    @property (nonatomic, strong, nullable) DoubleLinkNode *next;//后继指针域
    +(instancetype)constructNodeWithData:(int)data;
    @end 
    //  DoubleLinkNode.m
    //  LinkListDemo
    //  Created by 夏远全 on 2019/9/24.
    #import "DoubleLinkNode.h"
    
    @implementation DoubleLinkNode
    
    +(instancetype)constructNodeWithData:(int)data {
        
        DoubleLinkNode *node = [[DoubleLinkNode alloc] init];
        node.data = data;
        node.next = nil;
        node.pre = nil;
        return node;
    }
    @end

     1、构造双向循环链表

    //1、构建一个双向链表
    DoubleLinkNode *head = [[DoubleLinkNode alloc] init];
    DoubleLinkNode *node1 = [DoubleLinkNode constructNodeWithData:1];
    DoubleLinkNode *node2 = [DoubleLinkNode constructNodeWithData:2];
    DoubleLinkNode *node3 = [DoubleLinkNode constructNodeWithData:3];
    head.next = node1;
    node1.next = node2;
    node1.pre = head;
    node2.next = node3;
    node2.pre = node1;
    node3.pre = node2;
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"构造双向链表为"];
    2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123

    2、插入节点

    2-1:在头部插入节点

    //双向链表:在头部插入节点
    +(void)insetNodeAfterHead:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        if (headNode.next == nil) {
            headNode.next = newNode;
            newNode.pre = headNode;
        }
        else{
            newNode.next = headNode.next; //当前节点后继指向的头结点后继
            newNode.pre = headNode;       //当前节点的前驱指向头结点
            headNode.next.pre = newNode;  //头结点的后继结点的前驱指向当前节点
            headNode.next = newNode;      //头结点的后继指向当前节点
        }
    }
    //从头部插入
    DoubleLinkNode *node4 = [DoubleLinkNode constructNodeWithData:4];
    [FuncontionHandler insetNodeAfterHead:node4 headNode:head];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表头部插入节点4后"];
    2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
    2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123

    2-2:在尾部插入节点

    //双向链表:在尾部插入节点
    +(void)insetNodeAfterTail:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        //设置偏移指针
        DoubleLinkNode *pNode = headNode;
        while (pNode.next != nil) {
            pNode = pNode.next;
        }
        pNode.next = newNode;
        newNode.pre = pNode;
    }
    //从尾部插入
    DoubleLinkNode *node5 = [DoubleLinkNode constructNodeWithData:5];
    [FuncontionHandler insetNodeAfterTail:node5 headNode:head];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表尾部插入节点5后"];
    2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
    2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123
    2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:41235

    2-3:在指定位置插入节点

    //双向链表:在指定位置插入节点
    +(void)insetNodeAtIndex:(int)k node:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        //设置偏移指针
        DoubleLinkNode *pNode = headNode;
        int i = 1;
        while (pNode!= nil && i<k) {
            pNode = pNode.next;
            i++;
        }
        if (i==k) {
            //与从头结点插入的方式是一样的方法
            newNode.next = pNode.next;
            newNode.pre = pNode;
            pNode.next.pre = newNode;
            pNode.next = newNode;
        }
    }
    //从指定位置插入
    DoubleLinkNode *node6 = [DoubleLinkNode constructNodeWithData:6];
    [FuncontionHandler insetNodeAtIndex:2 node:node6 headNode:head];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表第2个位置插入节点6后"];
    2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
    2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123
    2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:41235
    2019-09-27 16:12:43.450262+0800 LinkList[39956:2129540] 在双向链表第2个位置插入节点6后:461235

    3、删除节点

    //双向链表:删除第k个位置的节点
    +(DoubleLinkNode *)deleteNodeAtIndex:(int)k headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return nil;
        }
        
        //设置偏移指针
        DoubleLinkNode *pNode = headNode.next;
        int i = 1;
        while (pNode!= nil && i<k) {
            pNode = pNode.next;
            i++;
        }
        if (i==k) {
            pNode.pre.next = pNode.next; //当前节点的前驱节点的后继指向当前节点的后继结点
            pNode.next.pre = pNode.pre;  //当前节点的后继结点的前驱指向当前节点的前驱节点
            return pNode;
        }
        return nil;
    }
    //3、删除节点
    DoubleLinkNode *deleteNode = [FuncontionHandler deleteNodeAtIndex:2 headNode:head];
    NSString *prefixText = [NSString stringWithFormat:@"删除第2个位置的节点%d后单链表为",deleteNode.data];
    [FuncontionHandler printFromHeadWithNode:head printPrefixText:prefixText];
    2019-09-27 16:12:43.449741+0800 LinkList[39956:2129540] 构造双向链表为:123
    2019-09-27 16:12:43.450118+0800 LinkList[39956:2129540] 在双向链表头部插入节点4后:4123
    2019-09-27 16:12:43.450209+0800 LinkList[39956:2129540] 在双向链表尾部插入节点5后:41235
    2019-09-27 16:12:43.450262+0800 LinkList[39956:2129540] 在双向链表第2个位置插入节点6后:461235
    2019-09-27 16:12:43.450336+0800 LinkList[39956:2129540] 删除第2个位置的节点6后单链表为:41235

    4、遍历双向循环链表

    //双向链表:遍历并打印链表
    +(void)printFromHeadWithNode:(DoubleLinkNode *)headNode printPrefixText:(NSString *)text {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        DoubleLinkNode *pNode = headNode.next;
        NSMutableArray *items = [NSMutableArray array];
        while (pNode!= nil) {
            [items addObject:@(pNode.data)];
            pNode = pNode.next;
        }
        NSLog(@"%@:%@",text,[items componentsJoinedByString:@""]);
    }

    三、源码

    FuncontionHandler.h

    //
    //  FuncontionHandler.h
    //  LinkList
    //
    //  Created by 夏远全 on 2019/9/27.
    //
    
    #import <Foundation/Foundation.h>
    #import "DoubleLinkNode.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface FuncontionHandler : NSObject
    
    //双向链表:在头部插入节点
    +(void)insetNodeAfterHead:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode;
    
    //双向链表:在尾部插入节点
    +(void)insetNodeAfterTail:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode;
    
    //双向链表:在指定位置插入节点
    +(void)insetNodeAtIndex:(int)k node:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode;
    
    //双向链表:删除第k个位置的节点
    +(DoubleLinkNode *)deleteNodeAtIndex:(int)k headNode:(DoubleLinkNode *)headNode;
    
    //双向链表:遍历并打印链表
    +(void)printFromHeadWithNode:(DoubleLinkNode *)headNode printPrefixText:(NSString *)text;
    
    @end
    
    NS_ASSUME_NONNULL_END
    View Code

    FuncontionHandler.m

    //
    //  FuncontionHandler.m
    //  LinkList
    //
    //  Created by 夏远全 on 2019/9/27.
    //
    
    #import "FuncontionHandler.h"
    
    @implementation FuncontionHandler
    
    //双向链表:在头部插入节点
    +(void)insetNodeAfterHead:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        if (headNode.next == nil) {
            headNode.next = newNode;
            newNode.pre = headNode;
        }
        else{
            newNode.next = headNode.next; //当前节点后继指向的头结点后继
            newNode.pre = headNode;       //当前节点的前驱指向头结点
            headNode.next.pre = newNode;  //头结点的后继结点的前驱指向当前节点
            headNode.next = newNode;      //头结点的后继指向当前节点
        }
    }
    
    //双向链表:在尾部插入节点
    +(void)insetNodeAfterTail:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        //设置偏移指针
        DoubleLinkNode *pNode = headNode;
        while (pNode.next != nil) {
            pNode = pNode.next;
        }
        pNode.next = newNode;
        newNode.pre = pNode;
    }
    
    //双向链表:在指定位置插入节点
    +(void)insetNodeAtIndex:(int)k node:(DoubleLinkNode *)newNode headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        //设置偏移指针
        DoubleLinkNode *pNode = headNode;
        int i = 1;
        while (pNode!= nil && i<k) {
            pNode = pNode.next;
            i++;
        }
        if (i==k) {
            //与从头结点插入的方式是一样的方法
            newNode.next = pNode.next;
            newNode.pre = pNode;
            pNode.next.pre = newNode;
            pNode.next = newNode;
        }
        
    }
    
    //双向链表:删除第k个位置的节点
    +(DoubleLinkNode *)deleteNodeAtIndex:(int)k headNode:(DoubleLinkNode *)headNode {
        
        //判空处理
        if (!headNode) {
            return nil;
        }
        
        //设置偏移指针
        DoubleLinkNode *pNode = headNode.next;
        int i = 1;
        while (pNode!= nil && i<k) {
            pNode = pNode.next;
            i++;
        }
        if (i==k) {
            pNode.pre.next = pNode.next; //当前节点的前驱节点的后继指向当前节点的后继结点
            pNode.next.pre = pNode.pre;  //当前节点的后继结点的前驱指向当前节点的前驱节点
            return pNode;
        }
        return nil;
    }
    
    //双向链表:遍历并打印链表
    +(void)printFromHeadWithNode:(DoubleLinkNode *)headNode printPrefixText:(NSString *)text {
        
        //判空处理
        if (!headNode) {
            return;
        }
        
        DoubleLinkNode *pNode = headNode.next;
        NSMutableArray *items = [NSMutableArray array];
        while (pNode!= nil) {
            [items addObject:@(pNode.data)];
            pNode = pNode.next;
        }
        NSLog(@"%@:%@",text,[items componentsJoinedByString:@""]);
        
    }
    
    @end
    View Code

    main方法

    //
    //  main.m
    //  LinkList
    //
    //  Created by 夏远全 on 2019/9/25.
    //
    
    #import <Foundation/Foundation.h>
    #import "FuncontionHandler.h"
    
    void testDoubleLink(void);
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
        
            testDoubleLink();
    
        }
        
        return 0;
    }
    
    void testDoubleLink(void){
        
        //1、构建一个双向链表
        DoubleLinkNode *head = [[DoubleLinkNode alloc] init];
        DoubleLinkNode *node1 = [DoubleLinkNode constructNodeWithData:1];
        DoubleLinkNode *node2 = [DoubleLinkNode constructNodeWithData:2];
        DoubleLinkNode *node3 = [DoubleLinkNode constructNodeWithData:3];
        head.next = node1;
        node1.next = node2;
        node1.pre = head;
        node2.next = node3;
        node2.pre = node1;
        node3.pre = node2;
        [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"构造双向链表为"];
        
        //2、从双向链表中插入节点
        DoubleLinkNode *node4 = [DoubleLinkNode constructNodeWithData:4];
        [FuncontionHandler insetNodeAfterHead:node4 headNode:head];
        [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表头部插入节点4后"];
     
        DoubleLinkNode *node5 = [DoubleLinkNode constructNodeWithData:5];
        [FuncontionHandler insetNodeAfterTail:node5 headNode:head];
        [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表尾部插入节点5后"];
        
        DoubleLinkNode *node6 = [DoubleLinkNode constructNodeWithData:6];
        [FuncontionHandler insetNodeAtIndex:2 node:node6 headNode:head];
        [FuncontionHandler printFromHeadWithNode:head printPrefixText:@"在双向链表第2个位置插入节点6后"];
        
        //3、删除节点
        DoubleLinkNode *deleteNode = [FuncontionHandler deleteNodeAtIndex:2 headNode:head];
        NSString *prefixText = [NSString stringWithFormat:@"删除第2个位置的节点%d后单链表为",deleteNode.data];
        [FuncontionHandler printFromHeadWithNode:head printPrefixText:prefixText];
        
    }
    View Code
  • 相关阅读:
    wav格式
    python字符串操作
    云中Active Directory是如何工作的?
    Azure Active Directory中的特权身份管理如何运作?
    工作组下的共享设置
    重新审视虚拟桌面存储
    NAND
    如何使用PowerShell管理Windows服务
    如何应对云爆发架构?四种方法替你解忧
    配置网络策略中的 NAP 条件
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/11598851.html
Copyright © 2011-2022 走看看