【数据结构】单链表

前言:小编这里将讨论无头单向非循环的单链表。

1.ArrayList的缺陷 

在上一期中,小编模拟了列表的相关操作实现,可以发现在增删的过程中非常麻烦,每次增加,或者删除数据的时候,都需要将操作下标的后面所有数据进行前移或者后移。

上期博客:http://t.csdnimg.cn/VI2yz

所以:

由于其底层是一段连续空间,当 ArrayList 任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后 搬移,时间复杂度为 O(n) ,效率比较低,因此 ArrayList 不适合做任意位置插入和删除比较多的场景 。因此: java集合中又引入了LinkedList ,即链表结构。

2链表的概念

链表是一种 物理存储结构上非连续 存储结构,数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的。
分类:
单向或者双向

带头或者不带头 

循环或者非循环

  

当然小编这里将讨论单向非循环; 

 3.链表的实现

3.1.初始化链表

 static class linknode{
        public int val;
        public linknode next;
        public linknode(int val){
            this.val=val;
        }
    }
    public linknode head;

首先定义一个类代表链表,在类中定义一个静态内部类,代表一个节点,节点内有值域,以及一个指针域。并在在构造函数中声明数值,方便在函数实例化时进行赋值操作,最后初始话一个头节点

3.2.链表赋值

 public void createList(){
        linknode node1=new linknode(12);
        linknode node2=new linknode(12);
        linknode node3=new linknode(14);
        linknode node4=new linknode(15);
        linknode node5=new linknode(16);
        linknode node6=new linknode(17);
        node1.next=node2;
        node2.next=node3;
        node3.next=node4;
        node4.next=node5;
        node5.next=node6;

        this.head=node1;
    }

实例化多个节点,并通过指针域进行相邻节点相连,但是小编不建议这么编写。

3.3.链表的头插法

 public void addFirst(int data){
        linknode node=new linknode(data);
        node.next=head;
        this.head=node;
    }

 图解:

所以 节点的next就为头结点,然后将头结点给node.

3.4.链表的尾插法

public void addLast(int data){
        linknode cur=head;
        linknode node=new linknode(data);
        while (cur.next!=null){
            cur=cur.next;
        }
        cur.next=node;
    }

与头插法相似,实例化节点,通过遍历链表,将cur节点next到链表末尾,最后通过cur节点指针域指向实例化的节点,实现尾插法。

3.5.在任意位置实现插入

public void addIndex(int index,int data){
        linknode cur=head;
        linknode node=new linknode(data);
        if (index==0){
            addFirst(data);
            return;
        }
        if (index==size()){
            addLast(data);
            return;
        }
        for (int i = 0; i <index-1; i++) {
            cur=cur.next;
        }
        node.next=cur.next;
        cur.next=node;
    }

判断插入位置是哪里,如果为0,即为头插法,如果为链表末尾,就是尾插法。

最后找到插入位置的前一个节点,通过改变指针域的指向地址,实现插入。

3.6.值是否存在链表中

 public boolean contains(int key){
        linknode cur=head;
        while (cur.next!=null){
            if (cur.val==key){
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

通过遍历每个节点,然后通过比较每个节点的数值域,如果存在则返回true,反之遍历完后,不存在则返回false。

3.7.删除第一次遇到的数值

 public void remove(int key){
        linknode cur=head;
        if (head.val==key){
            head=head.next;
            return;
        }
        while (cur.next!=null){
            if(cur.next.val==key){
                cur.next=cur.next.next;
                return;
            }
            cur=cur.next;
        }
    }

首先判断头结点的数值域是否等于key,等于就将头结点等于下一个节点。

反之遍历链表,如果存在该数值,就应该在数值的前一个节点进行操作,实现要删除节点的跳过操作。

3.8.实现所有key数值的删除

 public void removeAllKey(int key){
        linknode cur=head;
        linknode prve=head;
        while (cur!=null){
            if (cur.val==key){
                prve.next=cur.next;
                cur=cur.next;
            }else {
                prve=cur;
                cur=cur.next;
            }
        }
        if(head.val==key){
            head=head.next;
        }
    }

图解

首先我们定义两个节点 等于头结点,其中cur每次循环都要指向下一个节点,且如果不存在key时,prve倒要保持在cur节点的前一个,如果发现了key,则通过prve进行跳过,若存在重复,则,再次通过cur进行判断,在次通过prve进行跳过实现链接。

最后由于,头结点没有判断,就要进行头结点的判断。

3.9.实现链表的长度以及打印

public int size(){
        int size=1;
        linknode cur=head;
        while (cur.next!=null){
            cur=cur.next;
            size++;
        }
        return size;
    }
    public void clear() {
        this.head=null;
    }
    public void display() {
        linknode cur=head;
        while (cur!=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
    }

通过遍历链表,在节点不为空的情况下,每次循环长度加一,并且进行每个节点数值域的打印。

4.结束语

小编下一期将进行单向链表的相关题目讲解,想了解的uu关注一下吧。

限于小编能力有限,可能存在一些错误,希望各位uu提出宝贵意见,望指正。

制作不易,麻烦给小编一个赞吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值