链表 (Linked List)

Posted lililixuefei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表 (Linked List)相关的知识,希望对你有一定的参考价值。

链表介绍:

  1. 链表是以节点的方式来储存,是链式存储;

  2. 每个节点包含 data 域,next 域:指向下一个结点;

  3. 链表的各个节点不一定是连续存储的;

  4. 链表分为带头结点链表 和 没有头结点的链表,根据实际需求来确定;

单链表的应用实例:

使用带 head 头的单向链表实现 ---水浒英雄排行榜管理完成对英雄人物的增删改查操作;

  1. 第一种方法在添加英雄时,直接添加到链表的尾部

  2. 第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示):

  3. 修改节点功能

    思路:(1)先找到该节点,通过遍历(2)temp.name = newHeroNode.name;temp.nickname= newHeroNode.nickname;

  4. 删除节点

package dataStructures.linkedList;
?
?
/**
 * @author : 雪飞oubai
 * @date : 2020/4/1 10:20
 */
public class SingleLinkedListDemo {
    public static void main(String[] args) {
        HeroNode heroNode1 = new HeroNode(1, "xuefei1", "oubai1");
        HeroNode heroNode3 = new HeroNode(3, "xuefei3", "oubai3");
        HeroNode heroNode2 = new HeroNode(2, "xuefei2", "oubai2");
        HeroNode heroNode5 = new HeroNode(5, "xuefei5", "oubai5");
        HeroNode heroNode4 = new HeroNode(4, "xuefei4", "oubai4");
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addByOrder(heroNode1);
        singleLinkedList.addByOrder(heroNode3);
        singleLinkedList.addByOrder(heroNode2);
        singleLinkedList.addByOrder(heroNode5);
        singleLinkedList.addByOrder(heroNode4);
//        singleLinkedList.list();
        HeroNode heroNode6 = new HeroNode(4, "xuefei188", "oubai4");
        singleLinkedList.updateHeroNode(heroNode6);
        singleLinkedList.del(5);
        singleLinkedList.list();
?
    }
}
?
// 定义SingleLinkedList 管理我们的英雄
class SingleLinkedList {
    // 先初始化一个头结点,头结点不动,不存放具体数据
    private HeroNode head = new HeroNode(0, "", "");
?
    // 添加节点到链尾
    public void add(HeroNode heroNode) {
        // 定义一个辅助变量
        HeroNode temp = head;
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = heroNode;
    }
?
    // 按英雄编号顺序添加
    public void addByOrder(HeroNode heroNode) {
        // 定义一个辅助变量
        HeroNode temp = head;
        boolean flag = false;
        while (true) {
            if (temp.next == null) {   // 说明 temp 已经在链表最后了
                break;
            }
            if (temp.next.no > heroNode.no) {    // 位置找到了,就在temp后面插入
                break;
            } else if (temp.next.no == heroNode.no) {  // 说明希望添加的节点的编号已经存在了
                flag = true;
                break;
            }
            temp = temp.next;
        }
        // 判断 flag 的值
        if (flag) {
            System.out.printf("准备插入的英雄编号已经存在了,不能加入
", heroNode.no);
        } else {
            // 插入到链表中 temp 的后面
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }
?
    // 根据英雄编号修改 英雄信息 ,编号不变
    public void updateHeroNode(HeroNode heroNode) {
        // 定义一个辅助变量
        HeroNode temp = head.next;
        boolean flag = false;
        while (true) {
            if (temp == null) {
                break;
            }
            if (temp.no == heroNode.no && (Integer) heroNode.no != null) {
                // 找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag) {
            temp.name = heroNode.name;
            temp.nickName = heroNode.nickName;
        } else {
            System.out.println("无对应编号的英雄!");
        }
    }
    //  删除对应编号英雄
    public void del(int no) {
        HeroNode temp = head;
        boolean flag = false;   //标志是否找到待删除节点
        while (true) {
            if (temp.next == null) {
                break;
            }
            if (temp.next.no == no) {
                // 找到待删除节点的前一个节点
                flag = true;
                break;
            }
            temp = temp.next;   // temp后移
        }
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.println("要删除的节点不存在");
        }
    }
?
    // 遍历整个链表
    public void list() {
        // 先判断链表是否为空
        if (head.next == null) {
            throw new RuntimeException("链表为空");
        }
        // 因为头结点不能动,因此我们需要一个辅助变量来遍历
        HeroNode temp = head.next;
        while (temp != null) {
            System.out.println(temp);
            temp = temp.next;
        }
    }
}
?
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 + ‘‘‘ +
                ‘}‘;
    }
}

单链表面试题

  1. 求单链表中有效节点的个数

// 获得单链表的节点的个数(如果是带头结点的,需求不统计头结点)
    /**
     * @param head 链表的头结点
     * @return     返回值就是有效节点的个数
     */
    public static int getLength(HeroNode head){
        if(head.next == null){
            return 0;
        }
        int length = 0;
        // 定义一个辅助变量
        HeroNode cur = head.next;
        while(cur != null){
            length++;
            cur = cur.next;
        }
        return length;
    }

 

  1. 查找单链表中倒数第 k 个节点

// 查找单链表中的倒数第K个节点
    public static HeroNode findLastIndexNode(HeroNode head, int index) {
        // 判断如果链表为空,返回 null
        if (head.next == null) {
            return null;    //没有找到
        }
        // 第一个遍历得到链表的长度(节点个数)
        int size = getLength(head);
        if (size <= 0 || index > size) {
            return null;
        }
        // 定义辅助变量,for循环定位倒数的index
        HeroNode cur = head.next;
        for (int i = 0; i < size - index; i++) {
            cur = cur.next;
        }
        return cur;
    }

以上是关于链表 (Linked List)的主要内容,如果未能解决你的问题,请参考以下文章

[leetcode]141. Linked List Cycle判断链表是否有环

LeetCode2.Linked List — Linked List Cycle II 链表环2

206. Reverse Linked List

LeetCode27.Linked List—Reverse Linked List l链表逆置

141. Linked List Cycle

List------Linked 链表