Java | 单链表

本文介绍了Java中单链表的概念,并详细讲解了如何通过MemberNode和SingleLinkedList类实现链表的操作,包括计算有效节点数量、查找倒数第k个节点、链表反转、使用栈从尾到头打印链表以及合并两个有序链表。还提供了相应的测试代码及输出结果。

单链表介绍

/*
 * 链表
 * 1. 链表是以节点的方式来存储的,是链式存储
 * 2. 每个节点包含data域,next域:指向下一个节点
 * 3. 链表的各个节点不一定是连续存储
 * 4. 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定
 * <p>
 * 单链表的应用举例
 * 使用带head头的单向链表实现 -> RunningMan成员管理完成对成员的增删改查操作:
 * 1. 第一种方法在添加成员时,直接添加到链表的尾部
 * 2. 第二种方法在添加成员时,根据年龄将成员插入到指定位置(加入时间相同根据年龄大小排序)
 * 3. 修改节点功能:通过遍历先找到该节点,再进行修改
 * 4. 删除节点
 */

MemberNode类

class MemberNode {
    private int id;
    private String name;
    private String info;    // 成员的信息
    private MemberNode next;

    public MemberNode(int id, String name, String info) {
        this.id = id;
        this.name = name;
        this.info = info;
        this.next = null;
    }

    public MemberNode(MemberNode node) {
        this.id = node.getId();
        this.name = node.getName();
        this.info = node.getInfo();
        this.next = null;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public MemberNode getNext() {
        return next;
    }

    public void setNext(MemberNode next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "MemberNode{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", info='" + info + '\'' +
                '}';
    }
}

SingleLinkedList类

public class SingleLinkedList {
    // 先初始化一个头节点,头节点不要动,不存放具体的数据
    private MemberNode head = new MemberNode(0, null, null);

    // 添加节点到单向链表
    // 1. 找到当前链表的最后节点
    // 2. 将最后这个节点的next指向新的节点
    public void add(MemberNode memberNode) {
        MemberNode h = head;
        while (h.getNext() != null) {
            h = h.getNext();
        }
        h.setNext(memberNode);
        System.out.println("添加成功");
        list();
    }

    // 第二种方式在添加英雄时,根据排名将英雄插入到指定位置
    // 如果已有这个id,则添加失败,并给出提示
    public void addById(MemberNode memberNode) {
        MemberNode h = head;
        while (h.getNext() != null) {
            if (h.getNext().getId() < memberNode.getId()) {
                h = h.getNext();
                continue;
            } else if (h.getNext().getId() == memberNode.getId()) {
                System.out.println("添加失败,已有该成员!");
                return;
            }
            break;
        }
        memberNode.setNext(h.getNext());
        h.setNext(memberNode);
        System.out.println("添加成功");
        list();
    }

    // 修改成员的信息,根据id来修改,即id不能改
    public void update(MemberNode memberNode) {
        MemberNode h = head;
        while (h.getNext() != null) {
            if (h.getNext().getId() != memberNode.getId()) {
                h = h.getNext();
                continue;
            } else if (h.getNext().getId() == memberNode.getId()) {
                h.getNext().setInfo(memberNode.getInfo());
                System.out.println("修改成功");
                list();
                return;
            }
        }
        System.out.println("修改失败,未找到该成员!");
    }

    // 删除节点
    public void del(int id) {
        MemberNode h = head;
        while (h.getNext() != null) {
            if (h.getNext().getId() != id) {
                h = h.getNext();
                continue;
            } else if (h.getNext().getId() == id) {
                h.setNext(h.getNext().getNext());
                System.out.println("删除成功");
                list();
                return;
            }
        }
        System.out.println("删除失败,未找到该成员!");
    }

    // 显示链表(遍历)
    public void list() {
        MemberNode h = head;
        if (h.getNext() == null){
            System.out.println("当前链表为空!");
            return;
        }
        while (h.getNext() != null) {
            h = h.getNext();
            System.out.println(h.toString());
        }
        System.out.println();
    }
}

单链表面试题

求单链表中有效节点的个数
public int size(){
    MemberNode h = head;
    int size = 0;
    if (h.getNext() == null){
        System.out.println("当前链表为空!");
        return 0;
    }
    while (h.getNext() != null) {
        h = h.getNext();
        size ++;
    }
    return size;
}
查找单链表中的倒数第k个节点
public MemberNode lastK(int k){
    int size = this.size();
    int count = 0;
    MemberNode h = head;
    if (h.getNext() == null){
        throw new RuntimeException("当前链表为空");
    }
    if (size - k + 1 <= 0){
        throw new RuntimeException("越界!");
    }
    while (h.getNext() != null) {
        h = h.getNext();
        count ++;
        if (count == size - k + 1){
            System.out.println(h.toString());
            return h;
        }
    }
    throw new RuntimeException("越界!");
}
单链表的反转
/*
    思路:
    1. 先定义一个链表SingleLinkedList reverseList = new SingleLinkedList()
    2. 从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseList的最前端
 */
public SingleLinkedList reverse(){
    SingleLinkedList reverseList = new SingleLinkedList();
    MemberNode h = head;
    while (h.getNext() != null){
        h = h.getNext();
        MemberNode temp = new MemberNode(h);
        temp.setNext(reverseList.getHead().getNext());
        reverseList.getHead().setNext(temp);
    }
    return reverseList;
}
从尾到头打印单链表(Stack栈方式)
public void showStack(){
    Stack<MemberNode> stack = new Stack<>();
    MemberNode h = head;
    MemberNode node = null;
    while (h.getNext() != null){
        h = h.getNext();
        node = new MemberNode(h);
        stack.push(node);
    }
    while (!stack.isEmpty()){
        System.out.println(stack.pop());
    }
}
合并两个有序的单链表,合并之后的链表依然有序
public SingleLinkedList merge(SingleLinkedList list){
    SingleLinkedList mergeList = new SingleLinkedList();
    MemberNode h1 = head;
    MemberNode h2 = list.getHead();
    MemberNode temp = null;
    while (h1.getNext() !=null && h2.getNext() != null){
        if (h1.getNext().getId() < h2.getNext().getId()){
            h1 = h1.getNext();
            temp = new MemberNode(h1);
        }else if (h1.getNext().getId() > h2.getNext().getId()){
            h2 = h2.getNext();
            temp = new MemberNode(h2);
        }else if (h1.getNext().getId() == h2.getNext().getId()){
            h1 = h1.getNext();
            h2 = h2.getNext();
            temp = new MemberNode(h2);
        }
        mergeList.add(temp);
    }
    if (h1.getNext() != null)
        mergeList.add(h1.getNext());
    if (h2.getNext() != null)
        mergeList.add(h2.getNext());
    return mergeList;
}

测试代码1

/*
    先后年龄排名:
    1.池石镇 2.刘在石 3.金钟国 4.Gary 5.HAHA 6.宋智孝 7.李光洙 8.宋仲基 9.全昭旻 10.梁世灿 11.Lizzy
 */
@Test
public void test(){
    SingleLinkedList runningMan = new SingleLinkedList();
    runningMan.list();
    System.out.println("RunningMan开始啦!");
    runningMan.add(new MemberNode(1, "池石镇","王鼻子"));
    runningMan.add(new MemberNode(2, "刘在石","刘姆斯·邦德"));
    runningMan.add(new MemberNode(3, "金钟国","能力者"));
    runningMan.add(new MemberNode(4, "Gary","狗哥"));
    runningMan.add(new MemberNode(5, "HAHA","时间支配者"));
    runningMan.add(new MemberNode(7, "李光洙","长颈鹿"));
    runningMan.add(new MemberNode(8, "宋仲基","同龄朋友"));
    runningMan.list();
    System.out.println("智孝加入!");
    runningMan.addById(new MemberNode(6, "宋智孝","懵智孝"));
    runningMan.list();
    System.out.println("Lizzy加入!");
    runningMan.addById(new MemberNode(11, "Lizzy","RM的维他命"));
    runningMan.list();
    System.out.println("Lizzy下车");
    runningMan.del(11);
    runningMan.list();
    System.out.println("宋仲基下车");
    runningMan.del(8);
    runningMan.list();
    System.out.println("金钟国信息修改");
    runningMan.update(new MemberNode(3, "金钟国","能力者、斯巴达国斯"));
    runningMan.list();
    System.out.println("刘在石信息修改");
    runningMan.update(new MemberNode(2, "刘在石","刘姆斯·邦德、蚂蚱"));
    runningMan.list();
    System.out.println("Gary下车");
    runningMan.del(4);
    runningMan.list();
    System.out.println("全昭旻、梁世灿加入");
    runningMan.addById(new MemberNode(10, "梁世灿","小不点"));
    runningMan.addById(new MemberNode(9, "全昭旻","女版李光洙"));
    runningMan.list();
    System.out.println("RunningMan要一直健健康康下去");

    // 错误操作测试
    runningMan.addById(new MemberNode(9, "全昭旻","女版李光洙"));
    runningMan.del(100);
    runningMan.update(new MemberNode(0, "全昭旻","女版李光洙"));
    System.out.println("\nRM成员数" + runningMan.size());
    runningMan.lastK(8);
    runningMan.lastK(1);
    //        runningMan.lastK(9); // 越界
    System.out.println("\n链表反转");
    SingleLinkedList reverseList = runningMan.reverse();
    reverseList.list();
    System.out.println("从尾到头打印单链表");
    runningMan.showStack();
}

输出结果1

当前链表为空!
RunningMan开始啦!
池石镇添加成功
刘在石添加成功
金钟国添加成功
Gary添加成功
HAHA添加成功
李光洙添加成功
宋仲基添加成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=4, name='Gary', info='狗哥'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=8, name='宋仲基', info='同龄朋友'}

智孝加入!
宋智孝添加成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=4, name='Gary', info='狗哥'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=8, name='宋仲基', info='同龄朋友'}

Lizzy加入!
Lizzy添加成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=4, name='Gary', info='狗哥'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=8, name='宋仲基', info='同龄朋友'}
MemberNode{id=11, name='Lizzy', info='RM的维他命'}

Lizzy下车
删除成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=4, name='Gary', info='狗哥'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=8, name='宋仲基', info='同龄朋友'}

宋仲基下车
删除成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=4, name='Gary', info='狗哥'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}

金钟国信息修改
修改成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者、斯巴达国斯'}
MemberNode{id=4, name='Gary', info='狗哥'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}

刘在石信息修改
修改成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德、蚂蚱'}
MemberNode{id=3, name='金钟国', info='能力者、斯巴达国斯'}
MemberNode{id=4, name='Gary', info='狗哥'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}

Gary下车
删除成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德、蚂蚱'}
MemberNode{id=3, name='金钟国', info='能力者、斯巴达国斯'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}

全昭旻、梁世灿加入
梁世灿添加成功
全昭旻添加成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德、蚂蚱'}
MemberNode{id=3, name='金钟国', info='能力者、斯巴达国斯'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=9, name='全昭旻', info='女版李光洙'}
MemberNode{id=10, name='梁世灿', info='小不点'}

RunningMan要一直健健康康下去
添加失败,已有该成员!
删除失败,未找到该成员!
修改失败,未找到该成员!

RM成员数8
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=10, name='梁世灿', info='小不点'}

链表反转
MemberNode{id=10, name='梁世灿', info='小不点'}
MemberNode{id=9, name='全昭旻', info='女版李光洙'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=3, name='金钟国', info='能力者、斯巴达国斯'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德、蚂蚱'}
MemberNode{id=1, name='池石镇', info='王鼻子'}

从尾到头打印单链表
MemberNode{id=10, name='梁世灿', info='小不点'}
MemberNode{id=9, name='全昭旻', info='女版李光洙'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=3, name='金钟国', info='能力者、斯巴达国斯'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德、蚂蚱'}
MemberNode{id=1, name='池石镇', info='王鼻子'}

测试代码2

@Test
public void mergeTest(){
    SingleLinkedList running = new SingleLinkedList();
    SingleLinkedList man = new SingleLinkedList();
    SingleLinkedList runingMan = new SingleLinkedList();
    System.out.println("合并两个有序的单链表");
    running.add(new MemberNode(1, "池石镇","王鼻子"));
    man.add(new MemberNode(2, "刘在石","刘姆斯·邦德"));
    man.add(new MemberNode(3, "金钟国","能力者"));
    running.add(new MemberNode(3, "金钟国","能力者"));    // 检验重复数据
    man.add(new MemberNode(5, "HAHA","时间支配者"));
    running.addById(new MemberNode(6, "宋智孝","懵智孝"));
    running.add(new MemberNode(7, "李光洙","长颈鹿"));
    man.addById(new MemberNode(10, "梁世灿","小不点"));
    running.addById(new MemberNode(9, "全昭旻","女版李光洙"));
    System.out.println("\nrunning");
    running.list();
    System.out.println("\nman");
    man.list();
    System.out.println("\nRuningMan");
    runingMan = running.merge(man);
    runingMan.list();
}

输出结果2

合并两个有序的单链表
池石镇添加成功
刘在石添加成功
金钟国添加成功
金钟国添加成功
HAHA添加成功
宋智孝添加成功
李光洙添加成功
梁世灿添加成功
全昭旻添加成功

running
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=9, name='全昭旻', info='女版李光洙'}


man
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=10, name='梁世灿', info='小不点'}


RuningMan
池石镇添加成功
刘在石添加成功
金钟国添加成功
HAHA添加成功
宋智孝添加成功
李光洙添加成功
全昭旻添加成功
梁世灿添加成功
MemberNode{id=1, name='池石镇', info='王鼻子'}
MemberNode{id=2, name='刘在石', info='刘姆斯·邦德'}
MemberNode{id=3, name='金钟国', info='能力者'}
MemberNode{id=5, name='HAHA', info='时间支配者'}
MemberNode{id=6, name='宋智孝', info='懵智孝'}
MemberNode{id=7, name='李光洙', info='长颈鹿'}
MemberNode{id=9, name='全昭旻', info='女版李光洙'}
MemberNode{id=10, name='梁世灿', info='小不点'}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值