链表(单链表,双链表,环形链表)

目录

链表的基本概念

单链表

双链表

    链表增加结点

根据索引添加节点

删除操作

环形链表


链表的基本概念

        链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素
的逻辑顺序是通过链表中的指针
链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素
的数据域,另一个是存储下一个结点地址的指针
域。

        链表不会像数组一样开辟一片连续的空间,比数组空间的利用率高,链表可以根据需要申请空间也可以释放空间,且申请的空间后链表的空间也不要求是连续的。链表的增删的效率比数组高,但是链表查找效率没有数组高。

单链表

        单向链表单链表是链表
的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针
进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量
指向列表中的下一个结点;

链表是由结点
构成,head指针指向第一个成为表头结点,而终止于最后一个指向NULL
的指针。

 该链表的头节点不添加数据,头节点的next变量存储了第一个变量的地址,第一个变量也存储了下一个节点的地址,依次类推可以得到一条链表。需要添加链表时在链表的最后节点的next变量添加一个新节点。

 删除链表可以先找到该节点的父节点将父节点的next指向该节点的子节点 (如上图要删除第二个节点)

public class Linked {
    private int date;//链表中的数据

    private Linked next;//下一个节点

    public Linked(){

    }

    public Linked(int date){
        this.date = date;
    }

    public void add(int date){//添加节点
        Linked linked = this;
        while (linked.next != null){
            linked=linked.next;
        }
        linked.next=new Linked(date);
    }

    public int get(int index){//获取节点中的数据
        Linked linked=this;
        for(int i=0; i <= index; i++){
            linked = linked.next;
            if(linked == null){
                throw new IndexOutOfBoundsException();
            }
        }
        return linked.date;
    }


    public int delete(int index){//删除节点并返回该节点的数据
        Linked linked=this;
        for(int i=0; i<index; i++){
            linked = linked.next;
            if(linked.next == null){
                throw new IndexOutOfBoundsException();
            }
        }
        int date = linked.date;
        linked.next = linked.next.next;
        return date;
    }

    public int  length(){//链表的长度
        Linked linked = this;
        int length = 0;
        while (linked.next != null){
            linked = linked.next;
            length++;
        }
        return length;
    }

    public void forEach(){//遍历链表
        Linked linked = this;
        while (linked.next != null){
            System.out.println(linked.next.date);
            linked = linked.next;
        }
    }
}

双链表

        双向链表也叫双链表,是链表的一种,它的每个数据结点
中都有两个指针
,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

    链表增加结点

根据索引添加节点

找到当前索引位置的父节点,将该节点加入该链表,将父节点的next指向新加入的节点,该节点的front指向该父节点,next指向该父节点原来的子节点。(这一步需要判断是否存在该子节点,存在才可以操作)将该子节点的front指向新节点中

添加元素到链表的最后

遍历找到最后的节点,加入该链表

删除操作

找到该索引所在的节点,将该节点的父节点的next指向

public class DoubleLinked {

    private int date;

    private DoubleLinked next;

    private DoubleLinked front;

    public void addNext(DoubleLinked linked){
        this.next = linked;
    }

    public void addFront(DoubleLinked linked){
        this.front = linked;
    }

    public boolean isEmpty(){//判断链表是否为空
        if(this.front == null && this.next == null){
            return true;
        }
        return false;
    }

    
    //添加元素至链表最后
    public void add(int date){
        DoubleLinked doubleLinked =this;
        while (doubleLinked.next!=null){
            doubleLinked=doubleLinked.next;
        }
        doubleLinked.next=new DoubleLinked(date);
        doubleLinked.next.front=doubleLinked;
    }


    //根据索引添加元素
    public void add(int index,int date){
        DoubleLinked doubleLinked=this;
        for (int i=0;i<index;i++){
            doubleLinked=doubleLinked.next;
        }
        DoubleLinked doubleLinked1 = new DoubleLinked(date);
        doubleLinked1.next=doubleLinked.next;
        doubleLinked1.front=doubleLinked;
        doubleLinked.next = doubleLinked1;
    }


    //根据索引删除节点
    public int delete(int index){
        DoubleLinked doubleLinked =this;
        if(doubleLinked.isEmpty()){
            throw new IndexOutOfBoundsException();
        }
        for(int i=0;i<index;i++){
            doubleLinked=doubleLinked.next;
            if(doubleLinked==null){
                throw new IndexOutOfBoundsException();
            }
        }
        doubleLinked.front.next=doubleLinked.next;
        if(doubleLinked.next!=null) {
            doubleLinked.next.front = doubleLinked.front;
        }
        return doubleLinked.date;
    }
    
    //遍历链表
    public void forEach(){
        DoubleLinked doubleLinked=this;
        while (doubleLinked.next!=null){
            System.out.println(doubleLinked.next.date);
            doubleLinked=doubleLinked.next;
        }
    }

    public DoubleLinked(int date){
        this.date=date;
    }

    public DoubleLinked(){}

}

环形链表

        循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。

 环形链表即在单链表的基础上加尾指针指向头节点形成的闭环链表。

下面这段代码简单实现了环形链表,且并未实现删除操作,删除操作可以根据需要去实现。如约瑟夫问题。或者像上面代码定义一个头节点根据索引删除,在定义的尾节点的上添加。下面这段代码只是为了帮助大家理解环形链表。

public class CircularLinked {

    private int date;

    private CircularLinked next;

    private CircularLinked tail;

    public CircularLinked(int date){
        this.date=date;
    }

    public CircularLinked(){

    }

    public boolean isEmpty(){
        return next==null;
    }

    public void add(int date){
        if(isEmpty()){
            this.date=date;
            this.next=this;
            tail = this;
        }else {
            CircularLinked circularLinked = new CircularLinked(date);
            circularLinked.next = tail.next;
            tail.next = circularLinked;
            tail = circularLinked;
        }
    }



    public int length(){
        if(isEmpty()){
            return 0;
        }
        int i=0;
        CircularLinked circularLinked = this;
        while (circularLinked!=tail){
            circularLinked = circularLinked.next;
            i++;
        }
        return i+1;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值