java实现单链表的建立(头插法和尾插法)

单链表

在这里插入图片描述
单链表(Single Linked List):

  • 单链表是一种链式存取的数据结构,用一组地址任意可能连续,也可能不连续)的存储单元存放线性表中的数据元素。
  • 链表中的数据是以结点来表示的,每个结点的构成
    data域–存放结点值的数据域
    next域–存放结点的直接后继的地址的指针域(链域)
  • 链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的
  • 单链表的每个结点只有一个next域
  • 头指针head:单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。
  • 终端结点无后继,故终端结点的指针域为空,即NULL。

单链表的两种建立方式

  • 单链表的建立有头插法、尾插法两种方法。

  • 单链表是用户不断申请存储单元和改变链接关系而得到的一种特殊数据结构,将链表的左边称为链头,右边称为链尾。

  • 头插法右端固定,向左延伸,最先得到的是尾结点

  • 尾插法左端固定,向右延伸,最先得到的是头结点

  • 画个图简单示意下两个的区别
    在这里插入图片描述

  • 实现思路分析

  1. 头插法
    头插法
  2. 尾插法
    尾插法
  • 代码实现
public class SingleLinkedListDemo {
    public static void main(String[] args) {
        PersonNode person1 = new PersonNode(1, "Mary", "董事长");
        PersonNode person2 = new PersonNode(2, "Bob", "总经理");
        PersonNode person3 = new PersonNode(3, "Tom", "架构师");
        PersonNode person4 = new PersonNode(4, "Jenny", "工程师");
        SingleLinkedList singleLinkedList = new SingleLinkedList();
//        System.out.println("头插法测试");
//        singleLinkedList.headInsert(person1);
//        singleLinkedList.headInsert(person2);
//        singleLinkedList.headInsert(person3);
//        singleLinkedList.headInsert(person4);
//        singleLinkedList.list();
        System.out.println("尾插法测试");
        singleLinkedList.tailInsert(person1);
        singleLinkedList.tailInsert(person2);
        singleLinkedList.tailInsert(person3);
        singleLinkedList.tailInsert(person4);
        singleLinkedList.list();
    }
}

/**
 * 链表
 */
class SingleLinkedList {
    // 定义一个头结点,不存储结点数据,只是用来指向链表的第一个元素
    private PersonNode head = new PersonNode(0, "", "");

    /**
     * 头插法
     *
     * @param node 待插入结点
     */
    public void headInsert(PersonNode node) {
        // 判断链表是否为空,如果为空,则将head.next指向node
        if (head.next == null) {
            head.next = node;
            return;
        }
        // 如果链表不为空,找到head.next,将node插入head和head.next之间
        PersonNode temp = head.next;
        head.next = node;  // head.next指向node
        node.next = temp;  // node.next指向之前的head.next
    }

    /**
     * 尾插法
     *
     * @param node 待插入结点
     */
    public void tailInsert(PersonNode node) {
        // 如果链表为空,直接head.next = node
        if (head.next == null) {
            head.next = node;
            return;
        }
        // 如果链表不为空,遍历查找最后一个结点
        PersonNode temp = head.next;
        while (true) {
            // 这里的条件注意下,使用temp.next==null,不要用temp==null, 两者的区别体会一下,我自己在写的时候就写成后者了
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        // 跳出循环后,temp即为我们要找的链表的最后一个结点,直接temp.next=node
        temp.next = node;
    }

    /**
     * 遍历打印链表结点数据
     */
    public void list() {
        // 如果链表为空,返回
        if (head.next == null) {
            System.out.println("链表为空。");
            return;
        }
        // 如果链表不为空,遍历
        // head标识链表的头部,不要动,定义一个临时引用,用来遍历链表
        PersonNode temp = head.next;
        while (true) {
            // 如果temp为空,说明链表已经到达尾部,跳出循环
            if (temp == null) {
                // 此时temp表示last.next = temp,即最后一个结点指向它
                break;
            }
            // 如果temp不为空,打印temp
            System.out.println(temp);
            // temp后移,继续遍历
            temp = temp.next;
        }
    }
}

/**
 * 结点
 */
class PersonNode {
    int no;
    String name;
    String job;
    PersonNode next;

    public PersonNode(int no, String name, String job) {
        this.no = no;
        this.name = name;
        this.job = job;
    }

    public PersonNode() {
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public PersonNode getNext() {
        return next;
    }

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

    @Override
    public String toString() {
        return "PersonNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", job='" + job +
                '}';
    }
}
  • 来测试总结一把
    在这里插入图片描述
    在这里插入图片描述
    使用两种方式先往链表添加4个personNode,然后list()遍历打印。
    注意观察两种方式的no编号和插入顺序比较
    我们添加的顺序是1,2,3,4;
    头插法插入后链表的顺序是4,3,2,1;
    尾插法插入后链表的顺序是1,2,3,4;
    我们可以得出结论:
    头插法(往head的后面插入)插入后链表的顺序与插入顺序相反,也就是逆序插入;
    尾插法(往链表尾部的后面插入)插入后链表的顺序与插入顺序相同,也就是顺序插入;
    这里的逆序和顺序是由单向链表只能单向检索的特性决定的,并不是真的逆序和顺序插入
    具体使用哪种方式,根据业务需求确定
  • 28
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值