数据结构与算法分析(java)-链表(单链表、双向链表、环形链表)

链表介绍

特点:1.链表是以节点的方式来存储的,链式存储。

2.每个节点包含data域,next域指向下一个节点。

3.链表各节点不一定连续存储。

4.链表分带头节点的链表和没有头节点的链表,根据实际需求确定。

1.单链表

1.1 带头结点的链表

头节点(head):1.不存具体的数据2.作用就是表示单链表头

增删改查代码实现:

(插入分为两种:1.直接插入表尾2.按照标号插入)

class  SingleLinkedList{
    //创建头节点,不存放具体的数值,不能动
    private Node head =new Node(0,"");
    //添加节点到链表的最后:找到当前链表的最后节点并将最后节点的next指向新的节点
    public void add(Node node){
        //因为head不能动,故需要一个辅助变量来帮助遍历
        Node temp =head;
        //遍历找到最后
        while (true){
            if (temp.next==null){
                break;
            }
            temp=temp.next;
        }
        //将最后节点的next指向新的节点
        temp.next=node;

    }
    //显示链表
    public void showlist(){
        //判断链表是否为空
        if (head.next==null){
            System.out.println("链表为空");
            return;
        }
        Node temp =head.next;
        while (true){
            //判断是否到链表最后
            if (temp==null){
                break;
            }
            //不为空则输出,已经重写了tostring
            System.out.println(temp);
            temp=temp.next;
        }

    }

    public void addByOrder(Node pokenode){
        Node temp=head;//原因同上,头节点不能动,用辅助节点帮助遍历找到位置
        //单链表所以需要找到添加位置的前一个结点
        boolean flag=false;//标识要插入的node的序号是否已存在
        while (true){
            if(temp.next==null){
                break;//已经在链表的最后
            }
            if(temp.next.number>pokenode.number){
                break;//位置找到就在temp的后面插入
            }
            else if(temp.next.number==pokenode.number){
                flag=true;//编号已存在
                break;
            }
            temp=temp.next;//后移遍历
        }
        if(flag){
            System.out.println("已存在编号不能加入");

        }
        else {
            pokenode.next=temp.next;
            temp.next=pokenode;
        }
    }
    //修改节点的信息,根据number编号来修改,即number不能改
    public void update(Node newnode){
        if (head.next==null){
            System.out.println("链表为空");
            return;
        }
        Node temp=head;
        boolean flag=false;
        while (true){
            if(temp==null){
                break;//到最后了
            }
            if (temp.number== newnode.number){
                //找到
                flag=true;
            }
            temp=temp.next;
        }
        if(flag){
            temp.name=newnode.name;
        }
        else {
            System.out.println("没有找到");
        }
    }
    public void delete(int no ){
        Node temp=head;
        boolean flag = false;
        while (true){
            if (temp.next==null){
                break;
            }
            if (temp.next.number==no){
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if (flag){
            temp.next=temp.next.next;
        }
        else {
            System.out.println("没找到");
        }

    }
}

2.双向链表:

弥补一些单链表的缺点:1.单链表查找只能是一个方向,双向链表可以向前向后

2.单向链表各项功能均需要依靠辅助节点temp,而双向链表可以实现自我删除

双向链表的功能实现:

1.遍历方式与单链表相同,只是可以有多个方向。

2.添加时(表尾)除了需要将temp的next指向新元素,还需要将新元素的pre指向temp

3.删除:双向链表可以实现自我删除某个节点,找到该节点后直接写入

temp.pre.next=temp.next; 

即完成了自删除,而与单链表相同的是,删除掉的节点成为无效引用,将被GC(垃圾回收机制)处理。

代码实现增删改查:

package dsanda;

public class doubleLinkedListtest {
    public static void main(String[] args) {
            System.out.println("test for doublelinkedlist");
        Node1 OBJ1=new Node1(1,"PIKA");
        Node1 OBJ2=new Node1(2,"ZHONGZI");
        Node1 OBJ3=new Node1(3,"JIENI");
        Node1 OBJ4=new Node1(4,"ZENGZENG");
        DoubleLinkedList doublelinkedList =new DoubleLinkedList();
        doublelinkedList.add(OBJ1);
        doublelinkedList.add(OBJ2);
        doublelinkedList.add(OBJ3);
        doublelinkedList.add(OBJ4);
        doublelinkedList.showlist();
        Node1 newnode =new Node1(4,"BENDAN");
        doublelinkedList.update(newnode);
        doublelinkedList.showlist();
    }
}
class Node1{
    public int number;
    public String name;
    public Node1 next;//指向下一个节点
    public Node1 pre;//指向前一个节点 默认均为null
    public Node1(int number,String name){
        this.number=number;
        this.name=name;
    }
    @Override
    public String toString(){
        return "Node no="+number+" "+"name="+name;
    }

}
class DoubleLinkedList{
    //创建头节点,不存放具体的数值,不能动
    private Node1 head =new Node1(0,"");
    public Node1 getHead(){
        return head;
    }
    public void add(Node1 node){
        //因为head不能动,故需要一个辅助变量来帮助遍历
        Node1 temp =head;
        //遍历找到最后
        while (true){
            if (temp.next==null){
                break;
            }
            temp=temp.next;
        }
        //将最后节点的next指向新的节点并让新节点的pre指向temp
        temp.next=node;
        node.pre=temp;

    }
    public void showlist(){
        //判断链表是否为空
        if (head.next==null){
            System.out.println("链表为空");
            return;
        }
        Node1 temp =head.next;
        while (true){
            //判断是否到链表最后
            if (temp==null){
                break;
            }
            //不为空则输出,已经重写了tostring
            System.out.println(temp);
            temp=temp.next;
        }

    }
    public void update(Node1 newnode){
        if (head.next==null){
            System.out.println("链表为空");
            return;
        }
        Node1 temp=head;
        boolean flag=false;
        while (true){
            if(temp==null){
                break;//到最后了
            }
            if (temp.number== newnode.number){
                //找到
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if(flag){
            temp.name=newnode.name;
        }
        else {
            System.out.println("没有找到");
        }
    }
   //从双向链表中删除时可以做到自删除
    public void delete(int no ){
        //判断是否为空
        if(head.next==null){
            System.out.println("链表为空");
            return;
        }
        Node1 temp=head.next;
        boolean flag = false;
        while (true){
            if (temp==null){//已经到了最后节点的next
                break;
            }
            if (temp.number==no){
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if (flag){
            temp.pre.next=temp.next;
            //如果需要删除的节点为左后一个,则不应执行下一句
            if(temp.next!=null){
            temp.next.pre=temp.pre;}
        }
        else {
            System.out.println("没找到");
        }

    }




}

3.环形链表

即最后一个节点的next指向第一个节点

引入 约瑟夫问题应用单向环形链表:

public class roundLinkedList {
    public static void main(String[] args) {
        roundSinglelinkedList roundSinglelinkedList=new roundSinglelinkedList();
        roundSinglelinkedList.addBoy(5);
        roundSinglelinkedList.showboy();
        roundSinglelinkedList.countBoy(1,2,5);
    }
}
class roundSinglelinkedList{
     private boy first=new boy(-1);
     //添加节点构建黄兴链表
    public void addBoy(int nums){
        if (nums<1){
            System.out.println("nums值不正确");
            return;
        }
        boy curboy=null;
        //使用for创建环形链表
        for (int i=1;i<=nums;i++){
            boy boy1=new boy(i);
            if (i==1){
                first=boy1;
                first.setNext(first);//成环
                curboy=first;//让cur指向第一个小孩
            }else {
                curboy.setNext(boy1);
                boy1.setNext(first);
                curboy=boy1;

            }
        }
    }
    public void showboy(){
        if (first==null){
            System.out.println("空");
            return;
        }
        //first不能动,利用辅助指针完成遍历
        boy curboy=first;
        while (true){
            System.out.println("小孩的编号为"+curboy.getNo());
            if (curboy.getNext()==first){
                break;//说明已经遍历完成
            }
            curboy=curboy.getNext();//后移
        }
    }
    //根据用户的输入计算出 出圈的顺序
    /*
    * @param startno从第几个小孩开始数
    * countnum 数几下
    * nums多少小孩在圈中
    * */
    public void countBoy(int startNo,int countNum,int nums){
        if (first==null||startNo<1||startNo>nums){
            System.out.println("参数输入有误,请重新输入");
            return;
        }
        //创建辅助指针
        boy helper = first;
        while (true){
            if (helper.getNext()==first){
                break;//说明helper指向最后成员的节点
            }
            helper=helper.getNext();
        }
        //小孩报数前,先让first和helper移动k-1次
        for (int j=0;j<startNo-1;j++){
            first=first.getNext();
            helper=helper.getNext();
        }
        //当小孩报数时,让first和helper 指针同时移动m-1次,然后出圈
        //循环至题中只有一个节点
        while (true){
            if (helper==first){
                //说明圈中只有一个节点
                break;
            }
            //让first和helper移动countnum-1次
            for(int j=0;j<countNum;j++){
                first=first.getNext();
                helper=helper.getNext();
            }
            System.out.println("出圈的是编号"+first.getNo());
            first=first.getNext();
            helper.setNext(first);
        }
        System.out.println("最后留在圈中的小孩编号为"+helper.getNo());
    }
}
//创建一个boy类表示一个节点
class boy{
    private int no;
    private boy next;
    public boy(int no){
        this.no=no;
    }

    public int getNo() {
        return no;
    }

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

    public boy getNext() {
        return next;
    }

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

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值