04_链表

 


  01_概念


02_单向链表


 03_单向循环链表

 


 04_双向链表


 05_单向链表Java代码实现

复制代码
package DataStructureReview;

import java.util.Stack;

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        //创建链表对象
        SingleLinkedList list = new SingleLinkedList();
        //创建节点数据
        HeroNode node1 = new HeroNode(0, "刘备", "刘玄德");
        HeroNode node2 = new HeroNode(1, "关羽", "关云长");
        HeroNode node3 = new HeroNode(2, "张飞", "张翼德");
        //add方法
        list.add(node1);
        list.add(node2);
        list.add(node3);
        //遍历链表
        list.printList();
        System.out.println("=====根据no删除节点======");
        System.out.println("删除对象为: " + list.delete(2));
        System.out.println("=====根据no删除节点后======");
        list.printList();
        System.out.println("=====根据no修改节点======");
        System.out.println("是否修改成功: " + list.update(new HeroNode(10, "曹操", "曹孟德")));
        System.out.println("=====根据no修改节点后======");
        list.printList();
        System.out.println("=====根据no正序添加节点======");
        list.addOrderBy(new HeroNode(5, "蒋介石", "中正"));
        list.addOrderBy(new HeroNode(3, "张作霖", "雨亭"));
        list.addOrderBy(new HeroNode(2, "秦琼", "叔宝"));
        System.out.println("=====根据no正序添加节点后======");
        list.printList();
        System.out.println("=====获取当前链表有效节点数======");
        System.out.printf("当前链表有效节点数为:%d \n", list.size());
        System.out.println("=====获取当前链表中倒数第K个节点数据======");
        System.out.println(list.getNodeByK(2));
        System.out.println("=====将当前链表反转,反转前======");
        list.printList();
        System.out.println("=====将当前链表反转,反转后======");
        list.reverSetList();
        list.printList();
        list.reverSetList();
        System.out.println("=====将当前链表反向遍历======");
        list.printByStack();
        System.out.println("=====链表合并前======");
        list.printList();
        System.out.println("=====链表合并后======");
        SingleLinkedList newlist = new SingleLinkedList();
        newlist.addOrderBy(new HeroNode(5, "汤二虎", "汤玉麟"));
        newlist.addOrderBy(new HeroNode(4, "汤二虎", "汤玉麟"));
        newlist.addOrderBy(new HeroNode(6, "鬼切", "刀鸣散华"));
        list.mergeList(newlist);
        list.printList();

    }
}

//单向链表类
class SingleLinkedList {
    //设置链表head节点
    private HeroNode head = new HeroNode(0, "", "");

    //add方法,在链表尾部添加
    public void add(HeroNode node) {
        //判断是否为空链表
        if (head.next == null) {
            head.next = node;
            return;
        }
        //遍历链表
        HeroNode temp = head.next;//辅助指针
        while (true) {
            if (temp.next == null) {
                temp.next = node;
                break;
            }
            temp = temp.next;
        }

    }

    //addOrderBy,根据数据节点no添加,排序添加
    public void addOrderBy(HeroNode node) {
        //判断是否为空链表
        if (head.next == null) {
            head.next = node;
            return;
        }
        //遍历链表
        HeroNode temp = head;//辅助指针
        boolean flag = false;
        while (true) {
            if (temp.next == null) {
                break;
            }
            if (node.no < temp.next.no) {
                flag = true;
                break;
            }
            if (node.no == temp.next.no) {
                throw new RuntimeException("编号为:" + node.no + " 的数据节点已存在!");
            }
            temp = temp.next;
        }
        //根据辅助指针找到插入的数据节点
        if (flag) {
            node.next = temp.next;
            temp.next = node;
        } else {
            temp.next = node;
        }

    }

    //delete方法,根据no删除节点
    public HeroNode delete(int no) {
        //判断是否为空链表
        if (head.next == null) {
            throw new RuntimeException("当前链表为空,无节点可删除");
        }
        //遍历链表
        HeroNode temp = head;//辅助指针
        boolean flag = false;
        while (true) {
            if (temp.next == null) {
                break;
            }
            if (temp.next.no == no) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //根据辅助指针找到要删除的节点,和它前一个节点
        //x:要删除的节点 y:要删除的前一个节点 z:要删除的后一个节点
        //y.next = z
        HeroNode result = temp.next;
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.printf("此链表中没有找到编号为:%d 的节点\n", no);
        }
        return result;

    }

    //update方法,根据no删除节点
    public boolean update(HeroNode node) {
        //判断是否为空链表
        if (head.next == null) {
            throw new RuntimeException("当前链表为空,无节点可修改");
        }
        //遍历链表
        HeroNode temp = head.next;//辅助指针
        boolean flag = false;
        while (true) {
            if (temp.no == node.no) {
                flag = true;
                break;
            }
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        //根据辅助指针找到要修改的节点数据
        if (flag) {
            temp.name = node.name;
            temp.nickname = node.nickname;
        } else {
            System.out.printf("此链表中没有找到编号为:%d 的节点\n", node.no);
        }
        return flag;
    }


    //遍历链表
    public void printList() {
        //判断是否为空链表
        if (head.next == null) {
            System.out.println("当前链表为空!");
            return;
        }
        //遍历链表
        HeroNode temp = head.next;//辅助指针
        while (true) {
            System.out.println(temp);
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
    }

    //获取当前链表的有效节点数
    public int size() {
        //判断是否为空链表
        if (head.next == null) {
            return 0;
        }
        //遍历链表
        HeroNode temp = head.next;//辅助指针
        int sum = 0;
        while (true) {
            sum++;
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        return sum;
    }

    //查找单链表中倒数第K个数据节点
    public HeroNode getNodeByK(int k) {
        //判断是否为空链表
        if (head.next == null) {
            System.out.println("当前链表为空!");
            return null;
        }
        //由于链表只能从head开始遍历,我们可以将倒数变正数
        //即倒数第K = size+1-k
        int size = size();
        if (k > size || k <= 0) {
            throw new RuntimeException("倒数第" + k + "节点不存在!");
        }
        HeroNode temp = head.next;
        for (int i = 1; i < size + 1 - k; i++) {
            temp = temp.next;
        }
        return temp;
    }

    //将当前链表反转
    /*思路1:定义个节点变量x,当前链表为list:y1-y2-y3
     *       从list中取出节点,依次添加到变量x后面:
     *       x-y1
     *       x-y2-y1
     *       x-y3-y2-y1*/
    public void reverSetList() {
        //链表为空或者节点数为1时,反转后为他本身
        if (head.next == null || head.next.next == null) {
            return;
        }

        HeroNode head1 = new HeroNode(0, "", "");
        HeroNode temp = head.next;
        HeroNode cur;
        //遍历链表
        while (true) {
            cur = temp.next;
            temp.next = head1.next;
            head1.next = temp;
            if (cur == null) {
                break;
            }
            temp = cur;
        }
        head = head1;


    }

    //反向遍历链表,要求:使用stack
    public void printByStack() {
        Stack stack = new Stack();
        //判断是否为空链表
        if (head.next == null) {
            System.out.println("当前链表为空!");
            return;
        }
        //遍历链表
        HeroNode temp = head.next;//辅助指针
        while (true) {
            stack.push(temp);
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        int sum = stack.size();
        for (int i = 0; i < sum; i++) {
            System.out.println(stack.pop());
        }
    }

    //将两个有序单链表合并,合并之后需要依然有序
    public void mergeList(SingleLinkedList newlist) {
        HeroNode newhead = newlist.head;
        //空链表判断
        if (head.next == null) {
            head = newhead;
            return;
        } else if (newhead.next == null) {
            return;
        }
        //遍历newlist
        HeroNode temp = newhead.next;
        HeroNode cur;
        while (true) {
            cur = temp.next;
            try {
                addOrderBy(temp);
            } catch (RuntimeException e) {
                System.out.printf("编号为 %d节点已经存在!\n",temp.no);
            }
            if (cur == null) {
                break;
            }
            temp = cur;
        }


    }

}

//数据节点类
class HeroNode {
    public int no;
    public String name;
    public String nickname;
    public 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 + '\'' +
                '}';
    }
}
复制代码

  06_双向链表Java代码实现

 

 

复制代码
package DataStructureReview;

public class DoubleLinkedListDemo {
    public static void main(String[] args) {
        //创建链表对象
        DoubleLinkedList list = new DoubleLinkedList();
        //创建节点数据
        Data node1 = new Data(0, "刘备");
        Data node2 = new Data(1, "关羽");
        Data node3 = new Data(2, "张飞");
        //add方法
        list.add(node1);
        list.add(node2);
        list.add(node3);
        //遍历链表
        list.printList();
        System.out.println("=====根据no删除节点======");
        System.out.println("删除对象为: " + list.delete(2));
        System.out.println("=====根据no删除节点后======");
        list.printList();
        System.out.println("=====根据no修改节点======");
        System.out.println("是否修改成功: " + list.update(new Data(0, "曹操")));
        System.out.println("=====根据no修改节点后======");
        list.printList();
        System.out.println("=====根据no正序添加节点======");
        list.printList();
        list.addOrderBy(new Data(5, "蒋介石"));
        list.addOrderBy(new Data(3, "张作霖"));
        list.addOrderBy(new Data(2, "秦琼"));
        System.out.println("=====根据no正序添加节点后======");
        list.printList();
        System.out.println("=====根据no删除节点======");
        list.printList();
        System.out.println("删除对象为: " + list.delete(5));
        System.out.println("=====根据no删除节点后======");
        list.printList();


    }
}

class DoubleLinkedList {
    //设置head节点,pre为null,next指向第一个节点
    public Data head = new Data(0, "");


    //add方法,无序添加(在尾部添加)
    public void add(Data node) {
        //空链表判断
        if (head.next == null) {
            head.next = node;
            node.pre = head;
            return;
        }
        //遍历链表
        Data temp = head.next;
        while (true) {
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        temp.next = node;
        node.pre = temp;
    }

    //addOrderBy,顺序添加(根据Data的no大小顺序)
    public void addOrderBy(Data node) {
        //判断是否为空链表
        if (head.next == null) {
            head.next = node;
            node.pre = head;
            return;
        }
        //遍历链表
        Data temp = head.next;//辅助指针
        boolean flag = false;
        while (true) {
            if (node.no < temp.no) {
                flag = true;
                break;
            }
            if (node.no == temp.no) {
                throw new RuntimeException("编号为:" + node.no + " 的数据节点已存在!");
            }
            if (temp.next == null) {
                break;
            }


            temp = temp.next;
        }
        //根据辅助指针找到插入的数据节点
        if (flag) {
            node.pre = temp.pre;
            node.next = temp;
            temp.pre.next = node;
            temp.pre = node;
        } else {
            temp.next = node;
            node.pre = temp;
        }
    }

    //delete,根据Data的no删除节点,双向链表,可实现自我删除
    public Data delete(int no) {
        //空链表判断
        if (head.next == null) {
            throw new RuntimeException("当前链表为空,无节点可删除!");
        }
        //遍历链表
        Data temp = head.next;
        boolean flag = false;
        while (true) {
            if (temp.no == no) {
                flag = true;
                break;
            }
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        if (flag) {
            //自我删除
            temp.pre.next = temp.next;
            if(temp.next != null){
                temp.next.pre = temp.pre;
            }
            return temp;
        } else {
            throw new RuntimeException("当前链表中没有编号为 " + no + "的数据节点!");
        }
    }

    //update,根据Data的no更新节点
    public boolean update(Data node) {
        //判断是否为空链表
        if (head.next == null) {
            throw new RuntimeException("当前链表为空,无节点可修改");
        }
        //遍历链表
        Data temp = head.next;//辅助指针
        boolean flag = false;
        while (true) {
            if (temp.no == node.no) {
                flag = true;
                break;
            }
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        //根据辅助指针找到要修改的节点数据
        if (flag) {
            temp.name = node.name;
        } else {
            System.out.printf("此链表中没有找到编号为:%d 的节点\n", node.no);
        }
        return flag;
    }

    //printList,遍历链表
    public void printList() {
        //空链表判断
        if (head.next == null) {
            System.out.println("当前链表为空!");
            return;
        }
        //遍历链表
        Data temp = head.next;
        while (true) {
            System.out.println(temp);
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }

    }
}

class Data {
    public int no;
    public String name;
    public Data pre;
    public Data next;

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

    @Override
    public String toString() {
        return "Data{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}
复制代码

07_单向环形链表Java代码实现(解决约瑟夫问题)

 

 

 

复制代码
package DataStructureReview;

public class CircleSingleLinkedDemo {
    public static void main(String[] args) {
        //创建环形链表对象
        CircleSingleLinked list = new CircleSingleLinked();
        list.add(new Person(1, "张有才"));
        list.add(new Person(2, "张作霖"));
        list.add(new Person(3, "张作福"));
        list.add(new Person(4, "张作相"));
        list.add(new Person(5, "张学良"));
        list.add(new Person(6, "张学民"));
        list.add(new Person(7, "张学诚"));
        list.add(new Person(8, "张首芳"));
        list.add(new Person(9, "张冠英"));
        //遍历list
        list.printList();
        System.out.println("=========约瑟夫问题==========");
        UtilList.josephuArr(list, 4, 3);
    }
}

class CircleSingleLinked {
    //设置head节点
    public Person head;

    //add方法,无序添加(尾部添加)
    public void add(Person node) {
        //空链表判断
        if (head == null) {
            head = node;
            node.next = node;
            return;
        }
        //遍历链表
        Person temp = head;
        while (true) {
            if (temp.next == head) {
                break;
            }
            temp = temp.next;
        }
        temp.next = node;
        node.next = head;
    }

    //delete方法,根据Person.num删除
    public Person delete(int num) {
        //空链表判断
        if (head == null) {
            throw new RuntimeException("当前链表为空!");
        }
        //遍历链表,获取到被删除元素的前一个元素
        Person temp = head;
        boolean flag = false;
        while (true) {
            if (temp.next.num == num) {
                flag = true;
                break;
            }
            if (temp.next == head) {
                break;
            }
            temp = temp.next;
        }
        Person cur = temp.next;
        if (flag) {
            //只有一个元素时,需要置空head指针
            if (temp.next == temp) {
                head = null;
            } else {
                //删除第一元素时,需要移动head指针
                if(temp.next == head){
                    head = temp.next.next;
                }
                temp.next = temp.next.next;

            }

        } else {
            throw new RuntimeException("并未找到编号为:" + num + "的数据节点");
        }
        return cur;
    }

    //printList方法
    public void printList() {
        //空链表判断
        if (head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        //遍历链表
        Person temp = head;
        while (true) {
            System.out.println(temp);
            if (temp.next == head) {
                break;
            }
            temp = temp.next;
        }
    }

}

class UtilList {
    /**
     * @param list
     * @param startNo  指定从哪个per.num = k 的对象数数
     * @param countNum 数几下(m),countNum>=1
     */

    public static void josephuArr(CircleSingleLinked list, int startNo, int countNum) {
        //判断编号是否在链表内
        //空链表判断
        if (list.head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        //遍历链表
        Person temp = list.head;
        boolean flag = false;
        while (true) {
            if (temp.num == startNo) {
                flag = true;
                break;
            }
            if (temp.next == list.head) {
                break;
            }
            temp = temp.next;
        }
        if (flag != true) {
            System.out.println("当前链表并未找到编号为:" + startNo + "的对象!");
            return;
        }

        while (true) {
            //遍历链表
            Person cur = temp;
            for (int i = 0; i < countNum - 1; i++) {
                cur = cur.next;
            }
            int num = cur.num;
            temp = cur.next;
            System.out.println(list.delete(num));

            if (list.head == null) {
                break;
            }

        }


    }
}

class Person {
    public int num;
    public String name;
    public Person next;

    public Person(int num, String name) {
        this.num = num;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                '}';
    }
}
复制代码

 

posted @   学而不思则罔!  阅读(158)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示