链表

链表(Linked List)的介绍

链表是有序的列表,它在内存中的存储方式如下图所示。

头指针为head,指向的地址是150,而150地址指向的节点data域是a1,next域是110;110指向的节点的data域是a2,next域是130;…;170指向的节点的data域是a5,next域为null。

地址data域next域
110a2130
头指针 150120
130a3180
140
150a1110
160
170a5null
180a4170
190

1、链表是以节点的方式进行存储的
2、每一个节点都包含data域:用来存放数据、next域:用来指向下一个节点
3、链表的各个节点之间不一定是连续存储的
4、链表分为带头结点的链表和不带头节点的链表,根据实际需求进行使用。

单链表(带头结点)的逻辑结构图
在这里插入图片描述

代码实现单链表的创建、添加数据(尾插)及遍历
public class SingleLinkedListDemo {
    public static void main(String[] args) {
        // 测试
        // 创建链表
        SingleLinkedList linkedList = new SingleLinkedList() ;
        // 创建节点对象
        HeroNode node1 = new HeroNode(1,"宋江","及时雨");
        HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode node3 = new HeroNode(3,"吴用","智多星");
        HeroNode node4 = new HeroNode(4,"林冲","豹子头");
        // 向链表中添加节点
        linkedList.addNode(node1);
        linkedList.addNode(node2);
        linkedList.addNode(node3);
        linkedList.addNode(node4);
        // 遍历链表
        linkedList.showList();
    }
}

// 定义heroNode表示节点对象
class HeroNode {
    int no ;            // 编号
    String name ;       // 名字
    String nickName ;   // 昵称
    HeroNode next ;     // 指向下一个节点

    public HeroNode(int no, String name, String nickName) {
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

// 定义SingleLinkedList 对英雄进行管理
class SingleLinkedList {
    // 初始化头节点,头节点不存放任何数据
    HeroNode head = new HeroNode(0,"","") ;

    // 添加节点到单向链表
    public void addNode(HeroNode heroNode) {
        // 创建一个辅助节点遍历链表
        HeroNode temp = head ;
        // 遍历单链表,找到单链表的最后一个节点
        while (temp.next != null) { // 当没找到最后一个节点时
            // 将temp指向下一个节点的next域
            temp = temp.next ;
        }
        // 将最后一个节点的next域改为传入的节点
        temp.next = heroNode ;
    }

    // 遍历并输出链表中的节点数据
    public void showList() {
        // 判断链表是否为空
        // 为空
        if(head.next == null) {
            System.out.println("链表为空");
            return;
        }
        // 不为空
        // 创建辅助节点
        HeroNode temp = head ;
        // 判断当前节点后是否存在其他节点
        // 存在
        while (temp.next != null) {
            // 指向下一个节点
            temp = temp.next ;
            // 输出该节点
            System.out.println(temp);
        }
    }
}

结果在这里插入图片描述

头插法

代码

// 添加节点到单向链表(头插法)
public void addNode(HeroNode heroNode) {
    // 创建一个辅助节点遍历链表
    HeroNode temp = head ;
    /*
        要想将节点添加到头节点后,
        首先要将该节点的next域指向head的next域
        然后需要head节点的next域指向该节点
     */
    // 将插入的节点的next域指向head的next域
    heroNode.next = temp.next ;
    temp.next = heroNode ;
}

结果
在这里插入图片描述

排序添加

代码

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        // 测试
        // 创建链表
        SingleLinkedList linkedList = new SingleLinkedList() ;
        // 创建节点对象
        HeroNode node2 = new HeroNode(2,"卢俊义","玉麒麟");
        HeroNode node1 = new HeroNode(1,"宋江","及时雨");
        HeroNode node4 = new HeroNode(4,"林冲","豹子头");
        HeroNode node3 = new HeroNode(3,"吴用","智多星");
        // 向链表中添加节点
//        linkedList.addNode(node1);
//        linkedList.addNode(node2);
//        linkedList.addNode(node3);
//        linkedList.addNode(node4);

        linkedList.addByNo(node1);
        linkedList.addByNo(node2);
        linkedList.addByNo(node3);
        linkedList.addByNo(node4);
        // 遍历链表
        linkedList.showList();
    }
}

// 根据英雄的no大小进行排序添加
public void addByNo(HeroNode heroNode) {
    // 创建辅助节点
    HeroNode temp = head ;
    // 根据no进行插入节点时需要先找出其应该插入的位置,所以我们要先对链表进行遍历并比较no
    // 不为空
    while (temp.next != null) {
        if(temp.next.no > heroNode.no) {    // 当当前节点的no大于要插入节点的no时,直接在其后插入
            heroNode.next = temp.next ;
            temp.next = heroNode ;
        }else if(temp.next.no == heroNode.no) { // 当no相同时
            System.out.println("该英雄已存在");
            return;
        }
        // 节点后移
        temp = temp.next ;
    }
    // 为空直接插到head后
    temp.next = heroNode ;
}

结果
在这里插入图片描述

修改节点
/**
 * 传入一个节点,根据no找链表中是否存在该节点,如果存在就进行修改,不存在就提示用户不存在
 * @param heroNode  传入的节点对象
 */
public void updateNode(HeroNode heroNode) {
    // 创建辅助节点
    HeroNode temp = head ;
    // 判断链表是否为空或到达链表的尾部
    while (temp.next != null) {
        if(temp.next.no == heroNode.no) { // 当找到该节点时
            temp.next.name = heroNode.name ;
            temp.next.nickName = heroNode.nickName ;
            return;
        }
        // 节点后移
        temp = temp.next ;
    }
    System.out.println("该节点不存在");
}
删除节点
/**
 * 传入一个int类型的参数,到链表中进行查找,若该链表存在则将其删除
 * @param no    英雄编号
 */
public void deleteNode(int no) {
    // 创建辅助节点
    HeroNode temp = head ;
    // 判断链表是否为空或到达链表的尾部
    while (temp.next != null) {
        if(temp.next.no == no) {
            temp.next = temp.next.next ;
            return;
        }
        // 节点后移
        temp = temp.next ;
    }
    System.out.println("该节点不存在");
}
双线链表

单向链表和双向链表的对比:
1、查找的方向只能是一个方向,而双向链表可以向前或向后查找
2、单向链表不能自我删除,需要靠辅助结点,而双向链表可以实现自我删除
在这里插入图片描述
双向链表的遍历、添加、修改、删除的操作思路

1、遍历双向链表时,可以从前遍历,也可以从后遍历,其遍历方法和单向链表一样。
2、添加节点(尾插)
(1)先找到链表的最后一个节点temp
(2)temp.next = newNode,将最后一个节点的next指向要插入的节点newNode
(3)newNode.pre = temp,将新节点的pre指向temp
3、修改节点时,只需要查找到这个节点进行data的改变即可
4、删除节点
(1)在双向链表中,节点可以实现自我删除
(2)找到要删除的节点temp
(3)temp.pre.next = temp.next,将要删除的节点的前一个节点的next指向要删除节点的后一个节点
(4)temp.next.pre = temp.pre,将要删除的节点的后一个节点的pre指向要删除节点的前一个节点

双向链表删除截节点的示意图在这里插入图片描述

public class DoubleLinkedListDemo {
    public static void main(String[] args) {
        // 创建一个双向链表
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList() ;
        // 创建节点
        LinkedNode node1 = new LinkedNode(1) ;
        LinkedNode node2 = new LinkedNode(2) ;
        LinkedNode node3 = new LinkedNode(3) ;
        LinkedNode node4 = new LinkedNode(4) ;
        // 将节点添加到双向链表
        doubleLinkedList.addNode(node1);
        doubleLinkedList.addNode(node2);
        doubleLinkedList.addNode(node3);
        doubleLinkedList.addNode(node4);
        // 遍历双向链表
        doubleLinkedList.listNode();
        System.out.println("----------------------");
        // 修改data=2的节点的data为5
        doubleLinkedList.updateNode(2 , 5);
        doubleLinkedList.listNode();
        System.out.println("----------------------");
        // 删除data=3的节点
        doubleLinkedList.deleteNode(3);
        doubleLinkedList.listNode();
    }
}

// 创建一个节点类
class LinkedNode {
    int no ;            // data属性
    LinkedNode pre ;    // 指向前一个节点
    LinkedNode next ;   // 指向后一个节点

    public LinkedNode(int no) {
        this.no = no;
    }

    @Override
    public String toString() {
        return "LinkedNode{" +
                "no=" + no +
                '}';
    }
}

// 创建一个双向链表的类
class DoubleLinkedList {
    // 初始化一个头节点,data为-1
    LinkedNode head = new LinkedNode(-1) ;

    // 返回头节点
    public LinkedNode getHead() {
        return head ;
    }

    // 遍历双向链表
    public void listNode() {
        // 当链表为空时
        if(head.next == null) {
            System.out.println("链表为空");
            return;
        }
        // 链表不为空时
        // 创建辅助节点
        LinkedNode temp = head ;
        while (temp.next != null) {
            temp = temp.next ;  // 节点后移
            System.out.println(temp);   // 输出
        }
    }

    /**
     * 添加节点,尾插法
     * @param linkedNode    要添加的节点
     */
    public void addNode(LinkedNode linkedNode) {
        // 创建一个辅助节点
        LinkedNode temp = head ;
        // 判断链表是否到最后
        // 没有到最后一个节点时
        while (temp.next != null) {
            temp = temp.next ;  // 节点后移
        }
        // 到最后一个节点时
        temp.next = linkedNode ;
        linkedNode.pre = temp ;
    }

    // 修改节点
    public void updateNode(int no , int n) {
        // 当链表为空时
        if(head.next == null) {
            System.out.println("链表为空");
            return;
        }
        // 创建一个辅助节点
        LinkedNode temp = head ;
        // 遍历查找链表中是否存在no=n的节点
        while (temp.next != null) {
            temp = temp.next ;
            if(temp.no == no) {
                temp.no = n;
                return;
            }
        }
        System.out.println("该节点不存在");
    }

    // 删除节点
    public void deleteNode(int n) {
        // 当链表为空时
        if(head.next == null) {
            System.out.println("链表为空");
            return;
        }
        // 创建一个辅助节点
        LinkedNode temp = head ;
        // 遍历查找链表中是否存在no=n的节点
        while (temp.next != null) {
            temp = temp.next;
            if(temp.no == n) {
                temp.pre.next = temp.next ;
                temp.next.pre = temp.pre ;
                return;
            }
        }
        System.out.println("该节点不存在");
    }
}

结果在这里插入图片描述

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值