java数据结构----链表学习

链表(单链表)

**定义:**单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
链表中的数据是以结点来表示的,
每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,
指针就是连接每个结点的地址数据

本篇文章只是记录一下学习链表和使用代码实现,文章有写的不好或不对的可以指出,初次写稿,多多见谅
我们开始吧:
1.首先我们需要理解链表的数据结构的组成吧,如下图
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020051921011868.jpg#pic_center)

链表中的每一个节点都包含两个部分: **data(数据域)和next(下一个节点指向)**

2. 链表的优缺点
优点:
1. 删除和修改快(相对于数组数据结构来说)
2. 链表存储是分散的空间地址(数组是连续性的存储地址,需要-一开始指定存储大小)
3. 扩展性好,
缺点:
1.查询慢,因为查询需要从头开始遍历查询(不能按索引位置查询)

3.代码实现如下

//定义一个链表类 基础类
class HearNode {
     
    public Integer code;
    public String name;
    public String nickName;//以上是data数据域的属性
    public HearNode next; //指针域

    public HearNode(Integer code, String name, String nickName) {
     
        this.code = code;
        this.name = name;
        this.nickName = nickName;
    }

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

再定义一个实现链表的curd操作方法类

//封装方法
class LianBiaoDemo {
     
    //初始化链表 定义头结点
    HearNode head = new HearNode(null, "", "");

    /**
     * 1 首先需要找到链表最后一个节点  将该节点next指向插入的节点数据即可
     *
     * @param hearNode
     */
    public void addList(HearNode hearNode) {
     
        HearNode hea = head;
        //如果hea 的下一个节点为null 则表示已经到了尾节点
        while (hea != null) {
     
            if (hea.next == null) {
     
                break;
            }
            hea = hea.next;
        }
        hea.next = hearNode;
    }

    /**
     * 获取头节点信心
     */
    public HearNode getFirst() {
     
        if (head.next == null) {
     
            System.out.println("该链表是空的 ~~~");
        }
        System.out.println(head.next);
        return  head.next;
    }

    /**
     * 获取尾节点信息
     */
    public void getLast() {
     
        if (head.next == null) {
     
            System.out.println("该链表是空的 ~~~");
        }
        HearNode last = head;
        while (true) {
     
            if (last.next == null) {
     
                break;
            }
            last = last.next;
        }
        System.out.println(last);
    }

    /**
     * 获取链表的有效节点数
     *
     * @return
     */
    public int getCount() {
     
        //首先做链表非空判断
        if (head.next == null) {
     
            System.out.println("此链表为空的 ~~~");
            return 0;
        }
        HearNode hea = head;
        //获取链表的长度
        int i = 0;
        while (hea.next != null) {
     
            hea = hea.next;
            i++;
        }
        return i;
    }

    /**
     * 链表反转
     */
    public void revserNodeList() {
     
        //先判断节点个数是否为等于1或者为空
        if (head.next == null || head.next.next == null) {
     
            return;
        }
        //定义一个辅助变量指针 来遍历原始的链表
        HearNode hea = head.next;
        //定义一个新的链表 只想当前节点【hea】的下一个节点
        HearNode next = null;
        //新的链表的头节点信息
        HearNode newHead = new HearNode(null, "", "");
        //遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表的newHead 的最前端
        while (hea != null) {
     
            //记录链表指针 记录信息
            next = hea.next;
            //新链表的头节点指向取出的数据信息
            hea.next = newHead.next;
            //获取到最新的节点信息放到变量链表的头节点
            newHead.next = hea;
            //循环遍历
            hea = next;
        }
        // 将链表的头节点指向变量节点的头节点   head.next -> newHead.next
        head.next = newHead.next;
    }


    /**
     * 获取链表中的第N个节点信息
     * 1. 首先需要获取到链表的总的长度  需要先遍历一边
     * 2.定义一个变量接收要获取的第几个节点信息  index
     * 3.得到长度之后  从链表的第一个开始遍历(总长度 - index)个 就可以得到
     * 4.如果找到就返回  没有找到就返回空
     *
     * @return
     */
    public HearNode getIndex(int index) {
     
        //首先做链表非空判断
        if (head.next == null) {
     
            System.out.println("此链表为空的 ~~~");
            return null;
        }
        //获取链表的长度
        int i = getCount();
        //然后判断  链表长度与获取指定index作比较 如果为空或者index为负数 则直接返回
        if (i < index || index <= 0) {
     
            System.out.println("该index超出链表的长度");
            return null;
        }
        HearNode hea = head.next;
        for (int j = 0; j < i - index; j++) {
     
            hea = hea.next;
        }
        return hea;
    }

    /**
     * 从尾打印链表数据
     * @param
     */
    public void  StackInfo(){
     
         //判断链表是否为空
        if (head.next ==null){
     
            return;
        }
        //获取头节点信息
        HearNode hea=head;
        Stack stack=new Stack();
        while (hea.next !=null){
     
            hea=hea.next;
            //进栈
             stack.push(hea);
        }
        while (!stack.empty()){
     
            // 出栈
            System.out.println("打印出来"+stack.pop());
        }
    }


    /**
     * 链表插入时按照大小排序
     * 1 我们采用头结点的形式进行添加数据  所以需要定义一个头结点信息  但是这个头结点不做修改
     * 2. 定义一个辅助变量 flag 来判断 循环接节点与插入的节点大小比对 如果当前节点的下一个节点比插入节点大  则将插入的节点放置到当前节点下个节点前即可
     *
     * @param hearNode
     */
    public void sortList(HearNode hearNode) {
     
        //定义一个头结点
        HearNode hea = head;
        boolean flag = false;
        //hea不为空则循环继续
        while (hea != null) {
     
            //如果hea的下一个节点为null 则表示到达最后一个节点
            if (hea.next == null) {
     
                break;
            }
            //这里也可以做一个判断  如果节点相同则不让它添加
            //判断 如果当前节点code 大于当前code 则将当前的数据放在当前节点之前
            //我们删除一个节点 需要找到删除节点的前一个节点
            if (hea.next.code > hearNode.code) {
     
                flag = true;
                break;
            }
            hea = hea.next;
        }
        //如果flag为ture 则将当前插入的数据放到当前节点之后
        if (flag) {
     
            hearNode.next = hea.next;
            hea.next = hearNode;
        } else {
     
            hea.next = hearNode;
        }
    }

    /**
     * 删除节点信息
     *
     * @param code
     */
    public void delteNode(int code) {
     
        //判断当前链表是否为空
        if (head.next == null) {
     
            System.out.println("当前链表为空~~");
        }
        //定义一个变量
        HearNode hea = head;
        //定义一个标志位 记录查询到删除的code
        boolean flag = false;
        while (hea != null) {
     
            if (hea.next == null) {
     
                break;
            }
            //如果当前节点的code等于删除的code 则表示找到了记录信息
            if (hea.next.code == code) {
     
                flag = true;
                break;
            }
            hea = hea.next;//后移遍历
        }
        //判断标志位是否为ture
        if (flag) {
     
            //表示找到了删除的数据信息
            hea.next = hea.next.next;
        } else {
     
            System.out.println("未找到删除的节点信息");
        }
    }

    /**
     * 查询连表数据信息
     */
    public void selectList() {
     
        if (head.next == null) {
     
            System.out.println("当前链表为空~~");
            return;
        }
        HearNode hea = head.next;
        while (hea != null) {
     
            System.out.println(hea);
            hea = hea.next;
        }
    }

    /**
     * 修改节点信息
     * 1 首先需要循环遍历 去匹配找到需要修改的节点信息
     *
     * @param updateCode
     */
    public void updateCode(int code, HearNode updateCode) {
     
        //判断头结点的下一个是否为空,如果为空则直接返回
        if (head.next == null) {
     
            return;
        }
        HearNode hea = head;
        //定义一个辅助变量 记录是否找到修改信息的数据
        boolean flag = false;
        while (hea != null) {
     
            if (hea.next == null) {
     
                break;
            }
            //判断当前节点的下一个数据的code是否修改的数据信息
            if (hea.next.code == code) {
     
                flag = true;
                break;
            }
            hea = hea.next;//循环遍历
        }
        //如果为ture则表示找到了
        if (flag) {
     
            hea.next.name = updateCode.name;
            hea.next.nickName = updateCode.nickName;
        } else {
     
            System.out.println("未找到需要修改的信息数据");
        }
    }


最后我们再对方法进行测试,如下:

public class LianBiao {
     
    public static void main(String[] args) {
     
        LianBiaoDemo lianBiaoDemo = new LianBiaoDemo();
		//进行数据添加操作
        HearNode node = new HearNode(9, "wang", "~~~");
        HearNode node01 = new HearNode(15, "li", "~~~");
        HearNode node02 = new HearNode(3, "tang", "~~~");
        HearNode node04 = new HearNode(6, "tang01", "~~~");
        HearNode node05 = new HearNode(6, "tang02", "~~~");

        lianBiaoDemo.sortList(node01);
        lianBiaoDemo.sortList(node);
        lianBiaoDemo.sortList(node02);
        lianBiaoDemo.sortList(node05);
        lianBiaoDemo.sortList(node04);

		//查询方法
        lianBiaoDemo.selectList();
        //删除
        System.out.println("删除钱");
        lianBiaoDemo.delteNode(9);
        lianBiaoDemo.delteNode(15);
        lianBiaoDemo.selectList();
		//修改
        System.out.println("修改前的数据信息~~~~");
        HearNode newHearNode = new HearNode(3, "修改", "修改成功");
        lianBiaoDemo.updateCode(3, newHearNode);
        lianBiaoDemo.selectList();

        //1.获取头节点信息
        System.out.println("头节点信息为====》");
        lianBiaoDemo.getFirst();
        //2.获取尾节点信息
        System.out.println("尾节点信息======》");
        lianBiaoDemo.getLast();
        //3.求单链表的有效节点数
        System.out.println("链表的有效长度:" + lianBiaoDemo.getCount());
        //4.获取链表的倒数第n个节点信息
        System.out.println("获取指定indexe链表的数据===》" + lianBiaoDemo.getIndex(5));
        //5.单链表的反转  例如  123 ==》 321   123456====》654321 类似与这种反转
        /**
         * 反转的思路如下
         * 1.方法有很多 可以利用链表 +队列 来实现反转操作      
         * 这个方法还是用链表来实现   不过需要借助一个链表来进行
         * 2. 定义一个新的链表
         */
        System.out.println("反转链表~~");
        lianBiaoDemo.revserNodeList();
        lianBiaoDemo.selectList();
        //6从尾到头打印单链表 (要求方式: 1. 反向遍历  2. stack栈)
        /**
         * 可以利用栈的先进后出进行实现
         */
        System.out.println("反转");
        lianBiaoDemo.StackInfo();
    }
}

以上就是链表学习的代码实现,不理解的可以手动敲一敲,现在学习视频很多,看懂了但是不代表就会写出来,手撸一下会起到记忆加倍的效果。

当然方法中有很多地方可以提取出来,比如链表的长度,我们可以利用一个全局辅助变量来记录,就不需要单独写一个方法来循环一遍了。。。。

以上就是分享的内容,不好之处欢迎提出,谢谢!

你可能感兴趣的:(数据结构)