链表

1 链表

  • 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。

2 单链表



  • 商品结点类
package com.acti.linkedList;

/**
 * author hongyeci
 * date 20220722
 * version 1.0
 * remark 单链表--商品类
 */
public class GoodsNode {
    private int goodsId;
    private String goodsName;
    private double goodsPrice;
    private GoodsNode next;

    public GoodsNode() {
    }

    public GoodsNode(int goodsId, String goodsName, double goodsPrice) {
        this.goodsId = goodsId;
        this.goodsName = goodsName;
        this.goodsPrice = goodsPrice;
    }

    public int getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(int goodsId) {
        this.goodsId = goodsId;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public double getGoodsPrice() {
        return goodsPrice;
    }

    public void setGoodsPrice(double goodsPrice) {
        this.goodsPrice = goodsPrice;
    }

    public GoodsNode getNext() {
        return next;
    }

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

    @Override
    public String toString() {
        return "GoodsNode{" +
                "goodsId=" + goodsId +
                ", goodsName='" + goodsName + '\'' +
                ", goodsPrice=" + goodsPrice +
                ", next=" + next +
                '}';
    }
}

  • 带有头结点的单链表
package com.acti.linkedList;


/**
 * author hongyeci
 * date 20220722
 * version 1.0
 * remark 带有头结点的单链表
 */
public class SingleLinkedList {
    private GoodsNode node = new GoodsNode(0,"头结点",0.0);

    /**
     * 增加结点-添加到末尾结点
     * @param goodsNode 商品结点
     */
    public void addNode(GoodsNode goodsNode){
        GoodsNode temp = node;
        while(true){
            if (temp.getNext() == null){
                break;
            }
            temp=temp.getNext();
        }
        temp.setNext(goodsNode);
    }

    /**
     * 指定位置插入值
     * 按照商品id值顺序插入到链表中
     * @param goodsNode
     */
    public void insertNode(GoodsNode goodsNode){
        GoodsNode temp = node;
        boolean flag = false;
        while(true){
            if (temp.getNext() == null){
                break;
            }
            if (temp.getNext().getGoodsId()>goodsNode.getGoodsId()){
                break;
            }else if (temp.getNext().getGoodsId() == goodsNode.getGoodsId()){
                flag = true;
                break;
            }
            temp=temp.getNext();
        }
        if (flag){
            throw new RuntimeException("不能插入重复的商品...");
        }else {
            goodsNode.setNext(temp.getNext());
            temp.setNext(goodsNode);
        }
    }

    /**
     * 修改指定结点data域信息
     * @param goodsNode
     */
    public void updateNode(GoodsNode goodsNode){
        GoodsNode temp = node;
        if (temp.getNext() == null){
            throw new RuntimeException("该链表为空链表,不能进行修改操作...");
        }
        boolean flag = false;
        while (true){
            //1 直到最后一个结点
            if (temp.getNext()==null){
                break;
            }
            //2 找到指定结点
            if (temp.getNext().getGoodsId()==goodsNode.getGoodsId()){
                flag = true;
                break;
            }
            temp = temp.getNext();
        }
        if (flag){
            //修改指定结点data域数据
            temp.getNext().setGoodsName(goodsNode.getGoodsName());
            temp.getNext().setGoodsPrice(goodsNode.getGoodsPrice());
        }else {
            throw new RuntimeException("未找到指定结点...");
        }
    }

    /**
     * 删除指定结点
     * 根据结点ID删除指定结点
     * @param goodsId
     */
    public void deleteNode(int goodsId){
        //判断链表是否为空
        if (node.getNext() == null){
            throw new RuntimeException("该链表为空链表,不能进行删除操作...");
        }
        GoodsNode temp = node;  //头结点
        boolean flag = false;   //是否做删除操作标识
        //遍历链表结点 获取指定结点
        while (true){
            //遍历至最后一个结点 退出遍历
            if (temp.getNext()==null){
                break;
            }
            //找到指定结点
            if (temp.getNext().getGoodsId()==goodsId){
                flag = true;
                break;
            }
            temp = temp.getNext();
        }
        if (flag){
            //删除操作
            temp.setNext(temp.getNext().getNext());
        }else {
            throw new RuntimeException("未找到指定删除结点...");
        }
    }


    /**
     * 获取当前单链表的结点个数
     * @return
     */
    public int lengthNode(){
        int length = 0;
        GoodsNode temp = node.getNext();
        while (temp!=null){
            length++;
            temp = temp.getNext();
        }
        return length;
    }

    /**
     * 查看链表元素
     */
    public void listNode(){
        if (node.getNext()==null){
            System.out.println("空链表...");
        }else {
            GoodsNode temp = node;
            while (true){
                if (temp.getNext()==null){
                    break;
                }
                temp = temp.getNext();
                System.out.println(temp);
            }
        }
    }

}

3 双链表



  • 图书结点类
package com.acti.linkedList;

/**
 * author hongyeci
 * date 20220725
 * version 1.0
 * remark 双链表--图书类
 */
public class BooksNode {
    private int id;
    private String name;
    private double price;
    private BooksNode pre; //双链表前驱结点
    private BooksNode next; //双链表后继结点

    public BooksNode() {
    }

    public BooksNode(int id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    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 double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public BooksNode getPre() {
        return pre;
    }

    public void setPre(BooksNode pre) {
        this.pre = pre;
    }

    public BooksNode getNext() {
        return next;
    }

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

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

  • 带有头结点的双链表
package com.acti.linkedList;

/**
 * author hongyeci
 * date 20220725
 * version 1.0
 * remark 带有头结点的双链表
 */
public class DoubleLinkedList {
    private BooksNode head = new BooksNode(0,"头结点",0.0);

    /**
     * 增加结点-添加到末尾结点
     * @param booksNode 图书结点
     */
    public void addNode(BooksNode booksNode){
        BooksNode temp = head;
        while(true){
            if (temp.getNext() == null){
                break;
            }
            temp=temp.getNext();
        }
        temp.setNext(booksNode);
        booksNode.setPre(temp);
    }

    /**
     * 指定位置插入值
     * 按照商品id值顺序插入到链表中
     * @param booksNode
     */
    public void insertNode(BooksNode booksNode){
        BooksNode temp = head;
        boolean flag = false;
        while(true){
            if (temp.getNext() == null){
                break;
            }
            if (temp.getNext().getId()>booksNode.getId()){
                break;
            }else if (temp.getId() == booksNode.getId()){
                flag = true;
                break;
            }
            temp=temp.getNext();
        }
        if (flag){
            throw new RuntimeException("不能插入重复的商品...");
        }else {
            if (temp.getNext()==null){
                temp.setNext(booksNode);
                booksNode.setPre(temp);
            }else {
                //1、当前结点的后继结点后继节点前驱指向新结点
                temp.getNext().setPre(booksNode);
                //2、新结点后继结点指向当前结点后继结点
                booksNode.setNext(temp.getNext());
                //3、新结点前驱结点指向当前结点
                booksNode.setPre(temp);
                //4、当前结点后继结点指向新结点
                temp.setNext(booksNode);
            }

        }
    }

    /**
     * 修改指定结点data域信息
     * @param booksNode
     */
    public void updateNode(BooksNode booksNode){
        BooksNode temp = head;
        if (temp.getNext() == null){
            throw new RuntimeException("该双向链表为空链表,不能进行修改操作...");
        }
        boolean flag = false;
        while (true){
            //1 直到最后一个结点
            if (temp.getNext()==null){
                break;
            }
            //2 找到指定结点
            if (temp.getId()==booksNode.getId()){
                flag = true;
                break;
            }
            temp = temp.getNext();
        }
        if (flag){
            //修改指定结点data域数据
            temp.setName(booksNode.getName());
            temp.setPrice(booksNode.getPrice());
        }else {
            throw new RuntimeException("未找到指定结点...");
        }
    }

    /**
     * 删除指定结点
     * 根据结点ID删除指定结点
     * @param id
     */
    public void deleteNode(int id){
        BooksNode temp = head;  //头结点
        //判断链表是否为空
        if (temp.getNext() == null){
            throw new RuntimeException("该链表为空链表,不能进行删除操作...");
        }
        boolean flag = false;   //是否做删除操作标识
        //遍历链表结点 获取指定结点
        while (true){
            //遍历至最后一个结点 退出遍历
            if (temp.getNext()==null){
                break;
            }
            //找到指定结点
            if (temp.getId()==id){
                flag = true;
                break;
            }
            temp = temp.getNext();
        }
        if (flag){
            //1、当前结点前驱结点的后继指向当前结点的后继结点
            temp.getPre().setNext(temp.getNext());
            //2、当前结点的后继结点前驱指向当前结点的前驱结点
            if (temp.getNext()!=null){
                temp.getNext().setPre(temp.getPre());
            }
        }else {
            throw new RuntimeException("未找到指定删除结点...");
        }
    }


    /**
     * 获取当前单链表的结点个数
     * @return
     */
    public int lengthNode(){
        int length = 0;
        BooksNode temp = head.getNext();
        while (temp!=null){
            length++;
            temp = temp.getNext();
        }
        return length;
    }

    /**
     * 查看链表元素
     */
    public void listNode(){
        if (head.getNext()==null){
            System.out.println("空链表...");
        }else {
            BooksNode temp = head;
            while (true){
                if (temp.getNext()==null){
                    break;
                }
                temp = temp.getNext();
                System.out.println(temp);
            }
        }
    }

}

4 单向环形链表-约瑟夫环

  • 设编号为1,2,...,n的n个人围坐成一圈,约定编号为k(1=<k<=n)的人开始从1报数,数到m的人出列,他的下一位又从1开始报数,数到m的人出列,依此类推,直到所有人都出列为止,由此产生一个出队编号的序列。
  • 节点类
package com.structure.linkedList;
/**
 * author hongyeci
 * date 20220829
 * version 1.0
 * remark 单向环形链表--结点类
 */
public class BoyNode {
    //结点编号
    private int boyNo;
    //指向下一个结点
    private BoyNode next;

    public BoyNode(int boyNo) {
        this.boyNo = boyNo;
    }

    public int getBoyNo() {
        return boyNo;
    }

    public void setBoyNo(int boyNo) {
        this.boyNo = boyNo;
    }

    public BoyNode getNext() {
        return next;
    }

    public void setNext(BoyNode next) {
        this.next = next;
    }
}
  • 单向循环链表-约瑟夫环
package com.structure.linkedList;

/**
 * author hongyeci
 * date 20220830
 * version 1.0
 * remark 单向环形链表--约瑟夫环
 */
public class CircleSingleLinkedList {

    private BoyNode firstNode = new BoyNode(-1);

    /**
     * 定义单向环形链表
     * @param nums 结点个数
     */
    public void initCircleSingleLinkedList(int nums){
        if (nums<1){
            System.out.println("结点个数不能小于1");
            return;
        }
        //定义辅助结点,新进的结点赋给辅助结点
        BoyNode temp = null;

        for (int i=1;i<=nums;i++){
            BoyNode newBoy = new BoyNode(i);

            if (i == 1){
                //首结点时
                firstNode = newBoy;
                firstNode.setNext(firstNode);
                temp = firstNode;
            }else {
                temp.setNext(newBoy);
                newBoy.setNext(firstNode);
                temp=newBoy;
            }
        }
    }

    /**
     * 遍历输出循环链表--链表结点的编号
     */
    public void showCircleList(){
        if (firstNode == null){
            System.out.println("该链表为空..");
            return;
        }
        BoyNode node = firstNode;
        while (true){
            System.out.printf("当前结点编号为:%d\n",node.getBoyNo());
            //遍历到最后一个结点时,退出
            if (node.getNext()==firstNode){
                break;
            }
            node = node.getNext();
        }
    }


    /**
     * 约瑟夫环问题:
     * 设编号为1,2,...,n的n个人围坐成一圈,约定编号为k(1=<k<=n)的人开始从1报数,数到m的人出列,
     * 他的下一位又从1开始报数,数到m的人出列,依此类推,直到所有人都出列为止,由此产生一个出队编号的序列。
     * @param startNo 开始结点
     * @param count 间隔结点数
     * @param nums 单向循环链表中结点个数
     */
    public void handle(int startNo,int count,int nums){
        if(startNo>nums || startNo<1 || firstNode==null){
            System.out.println("参数错误..");
            return;
        }
        //定义辅助结点,指向最后一个结点
        BoyNode lastNode = firstNode;
        while (true){
            if (lastNode.getNext() == firstNode){
                //找到最后结点时退出
                break;
            }
            lastNode = lastNode.getNext();

        }
        //确定编号为startNo的结点移动次数startNo-1 找到firstNode、lastNode
        for(int i=0;i<startNo-1;i++){
            firstNode = firstNode.getNext();
            lastNode = lastNode.getNext();
        }
        //开始数数,数到count的结点出列
        while (true){
            if (lastNode == firstNode){
                //单项循环链表中只剩一个结点时 出列
                System.out.printf("最后一个结点%d出列\n",firstNode.getBoyNo());
                break;
            }
            //数数
//            firstNode.setBoyNo(firstNode.getBoyNo()+(count-1));
//            lastNode.setBoyNo(lastNode.getBoyNo()+(count-1));
            for (int i=0;i<count-1;i++){
                firstNode = firstNode.getNext();
                lastNode = lastNode.getNext();
            }
            //出列
            System.out.printf("结点%d出列\n",firstNode.getBoyNo());
            //构成循环链表
            firstNode = firstNode.getNext();
            lastNode.setNext(firstNode);
        }
    }

}

数据结构相关代码仓库地址:
https://gitee.com/red_leafzsp/structureAlgorithms

posted on 2022-08-30 14:36  红叶次  阅读(94)  评论(0编辑  收藏  举报