数据结构—链表之单向链表

数据结构—链表之单向链表


前言

本文主要介绍数据结构之单向链表的实现思路和代码用例。


提示:以下是本篇文章正文内容

单向链表

一、单向链表介绍

基本概念 : 链表一种线性的数据结构,通过指针将一个个零散的内存块连接起来,链表的每个内存块称为结点。
通过概念我们可以知道一下几点

  1. 链表也是一种线性结构,之前介绍过的线性结构有数组和队列,链表也是其中之一
  2. 链表是内存不连续的,是通过指针将内存块(节点)链接起来的
  3. 不连续的内存相比数组来说好处就是插入或者删除元素的时候(数组尾部操作忽略),不会移动后面所有元素保持内存结构连续性,所以他的插入和删除的时间复杂度是O(1),当然遍历的时间复杂度是O(n),增删比较快

  通过链表的概念推断出来以上几点,下面介绍下使用JAVA实现单向链表的实现思路。

二、单向链表实现思路

1.实现思路

假如需要按照分数由高到低存储学生的学号和成绩,使用链表实现的话怎么做,先来一张链表的图
在这里插入图片描述
从图中可以看到

  1. 链表每个节点都是由数据和指针组成的,如果想要实现一个链表,首先需要有节点,这里的节点就是学生的学号,姓名,分数信息,同时每个节点持有一个next指针
  2. 有了节点怎么创建链表呢?从图中看到,这个链表首先是有一个头节点,每新增一个节点,前面一个节点的指针按照分数与当前节点(currNode)的下一个节点的分数做比较,然后决定是插入到当前节点之后还是当前节点下一个节点之后,这个可以通过遍历整个链表来实现,比较简单,当需要新增节点时,从链表头部(head)开始遍历,head的下一个节点如果为空,说明是空链表,直接把当前插入的节点赋值给head.next即可;如果head.next不为空,插入的学生节点的分数与head.next的节点的分数进行比较,如果插入的节点分数高,就把head.next指向插入的节点,把插入节点的指针指向之前head.next的节点即可,依次类推即可实现
  3. 删除节点与插入节点十分相似,这里是根据学生编号进行删除,可以参考插入节点的实现方式
  4. 遍历链表,直接循环打印即可
2.代码示例
package link;

import org.apache.commons.lang.StringUtils;

public class MySingleLinkedTest {

    public static void main(String[] args) {

        StudentNode s1 = new StudentNode(1,"小明",90);
        StudentNode s2 = new StudentNode(2,"小红",80);
        StudentNode s3 = new StudentNode(3,"小蓝",70);
        StudentNode s4 = new StudentNode(4,"小张",60);
        StudentNode s5 = new StudentNode(5,"小绿",60);
        StudentNode s6 = new StudentNode(6,"小黑",100);

        MySingleLinked singleLinked = new MySingleLinked();
        singleLinked.addNode(s1);
        singleLinked.addNode(s3);
        singleLinked.addNode(s2);
        singleLinked.addNode(s5);
        singleLinked.addNode(s6);
        singleLinked.addNode(s4);

        singleLinked.showLinked();

        StudentNode studentNode = singleLinked.deleteNode(5);
        System.out.printf("删除的链表节点 : %s  \n",studentNode.toString());
        System.out.println("删除之后的链表 : ");
        singleLinked.showLinked();
        //再次删除
        singleLinked.deleteNode(5);


    }

}

class MySingleLinked{

    public StudentNode head = new StudentNode(0,"head",0);
    /**
     * 链表打印
     */
    public void showLinked(){
        if (null == head.next){
            System.out.println("链表为空!");
        }
        StudentNode studentNode = head.next;
        while(true){
            System.out.println(studentNode);
            if(null == studentNode.next){
                break;
            }else{
                studentNode = studentNode.next;
            }
        }
    }
    /**
     * 新增节点
     * 按照分数节点由高到底插入
     */
    public void addNode(StudentNode student){
        //基本参数校验
        if(null == student){
            throw new RuntimeException("入参节点非法!");
        }
        //基本参数校验
        if(student.getScore() < 0
                || StringUtils.isBlank(student.getName())
                || student.getNo() < 0){
            throw new RuntimeException("入参节点学生信息的数据为空!");
        }
        StudentNode currNode = head;//当前节点
        while(true){
            if(null == currNode.next){//循环到链表尾部,直接添加
                currNode.next = student;
                break;
            }
            //单向链表只能在当前位置的后面添加,按分数比较需要与当前节点后面节点去比较
            if(student.getScore() > currNode.next.getScore()){
                //如果把下面两行代码交换下位置可以跑跑试试,比较有意思
                student.next = currNode.next;
                currNode.next = student;
                break;
            }else{
                currNode = currNode.next;
            }
        }
    }

    /**
     * 删除制定序号的节点,并返回该节点
     * 与新增类似,这里使用两个指针实现,也可以与新增一样使用单指针实现
     */
    public StudentNode deleteNode(int no){
        //基本校验
        if(null == head.next){
            throw new RuntimeException("链表为空!");
        }
        //基本参数校验
        if(no <= 0){
            throw new RuntimeException("学生编号非法!");
        }
        StudentNode currNode = head.next;//当前节点
        StudentNode currBeforeNode = head;//当前节点的前一个节点
        while(true){
            int currNodeNo = currNode.getNo();
            if(no == currNodeNo){
                currBeforeNode.next = currNode.next;
                return currNode;
            }else{
                if(null == currNode.next){
                    break;
                }
                currBeforeNode = currNode;
                currNode = currNode.next;
            }
        }
        System.out.printf("学号 【%s】 不存在!\n",no);
        return null;
    }

}

class StudentNode{

    private int no;//学号
    private String name;//学生姓名
    private int score;//学生分数
    public StudentNode next;//指针

    public StudentNode() {
    }

    public StudentNode(int no, String name, int score) {
        this.no = no;
        this.name = name;
        this.score = score;
    }

    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 int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

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

总结

单向链表简单介绍到这里,如果问题请各位大神积极指教

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值