链表(单向链表 双向链表)

链表

注意:

【1】链表的插入和删除不是所有情况下都比顺序表快,比如尾插尾删,顺序表的时间复杂度为O(1),并且如果是单链表,如果要在中间某个节点的前面插入/删除一个节点,则需要遍历。所以时间的快慢要分情况看待。

数组是在物理和逻辑上都连续,而,链表是只在逻辑上连续,但在物理上不连续的

在这个的next域存储下一个的地址,这样我们就知道这个节点指向哪一个节点了
在这里插入图片描述
这种链表是:单向,不带头,非循环链表
这种链表我们一旦找到第一个,后面的节点我们就全都都知道了

链表分类

在这里插入图片描述
这两种重要!

单链表

在这里插入图片描述
有head指向的节点,我们叫这种链表是带头的
在这里插入图片描述

如果是循环的,那么最后一个节点的next域就不是null了,而是指向上图中箭头所指的这个节点的地址

链表的定义

在这里插入图片描述

链表的创键

在这里插入图片描述

链表的方法

方法一:链表的遍历,全部打印出来

相当于数组遍历,这个是让链表打印完全部值,往后走
在这里插入图片描述
但是这样写有一个非常严重的问题,如果你要让head走的话,那你最后就不知道head的到底指向哪一个;了,所以我们不行这么写,我们要让cur走,而不是让head走
在这里插入图片描述
这样走完我们head指向的永远是第一个节点,一定要这样写!!!!

方法二:查找是否包含值为key的value

在这里插入图片描述

方法三:得到单链表的长度

在这里插入图片描述

方法四:头插法(一般来说我们一般用头插法来创建链表)

将一个新的节点插入到当前头节点的前面
我们一般建议在插入的时候,先绑定后面的节点信息
在这里插入图片描述
在这里插入图片描述

方法五:尾插法

在这里插入图片描述

PS:因为头插法是放进去当第一个节点,所以不管链表是否为空,都可以插入,而尾插法是放进去当最后一个节点的,所以当链表为空的时候,不能null后面还有node,所以直接把node赋给cur
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法六:在指定位置插入元素

在这里插入图片描述
在这里插入图片描述

方法七:删除第一次出现的关键字key

在这里插入图片描述
在这里插入图片描述

方法八:清空链表

在这里插入图片描述

注意:
在这里插入图片描述
在这里插入图片描述
对于这道题我们要注意的问题就是,在插入s的时候,我们的顺序是先连接s,再断开p

练习题1

通过遍历一遍将要删除的数字都删掉,此处要删的是23;
在这里插入图片描述
在这里插入图片描述
如果要删的数字在第一个节点,那么我们就把循环全部走完之后再来判断是否第一个也为要删除的数字

讲了吗

在这里插入图片描述

在这里插入图片描述

双向链表

LinkedList的模拟实现

public class MyLinkedList {//双向链表和单链表最大的不同点就是双向链表自带一个last,就不用像单链表一样再遍历一遍

    static class ListNode {
        private int val;
        private ListNode prev;
        private ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode head;
    public ListNode last;
    
    public int size() {
        ListNode cur = head;
        int len = 0;
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }

    public void display() {
        ListNode cur = head;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
    }

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

    //头插法
    public void addFirst(int data) {
        ListNode node = new ListNode(data);
        if (head == null) {
            head = node;
            last = node;
        } else {
            node.next = head;
            head.prev = node;
            head = node;
        }
    }

    //尾插法
    public void addLast(int data) {
        ListNode node = new ListNode(data);
        if (head == null) {
            head = node;
            last = node;
        } else {
            last.next = node;
            node.prev = last;
            last = node;
        }
    }

    //任意位置插入,第一个元素下标为0
    public void addIndex(int index, int data) {
        cheakIndex(index);
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        ListNode cur = searchIndex(index);
        ListNode node = new ListNode(data);
        node.next = cur;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;

    }

    private ListNode searchIndex(int index) {
        ListNode cur = head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }

    private void cheakIndex(int index)  {//抛出不合法性
        if (index < 0 || index > size()) {
            throw new IndexOutOf("index不合法!" + index);//重要!抛出不合法
        }
    }
```java
//删除第一个关键字key的值
    //分三步来,(1)删除头节点(2)删除尾节点(3)删除中间节点
    public void remove(int key) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {//找到要删除的key,用三步进行循环
                if (cur == head) {//key为第一个节点
                    head = head.next;
                    if (head != null) {
                        head.prev = null;
                    } else {
                        last = null;//else说明这个双向链表只有一个节点,所以将last也置空
                    }
                } else {//key为中间节点或者最后一个节点
                    if (cur.next != null) {
                        cur.prev.next = cur.next;
                        cur.next.prev = cur.prev;
                    } else {//删除key为最后一个节点
                        last = last.prev;
                        last.next = null;//老师写的是:cur.prev.next=cur.next;last=last.prev;
                    }
                }
                return;
            } else {
                cur = cur.next;
            }
        }
    }
public void clear(){
        ListNode cur=head;
        while(cur!=null){
            ListNode th=cur;
            cur.prev=null;
            cur.next=null;
            cur=th.next;
        }
        head=null;//记得给他手动置空,不然last和head还在呢
        last=null;
    }
public static void main(String[] args) {
    MyLinkedList myLinkedList=new MyLinkedList();
   myLinkedList.addFirst(5);
   myLinkedList.addFirst(4);
   myLinkedList.addFirst(3);
   myLinkedList.addFirst(2);
   myLinkedList.addFirst(1);
   myLinkedList.addLast(6);
    //System.out.println(myLinkedList.size());

    /*boolean ret=myLinkedList.contains(6);
    System.out.println(ret);*/
    myLinkedList.addIndex(2,9);
    myLinkedList.display();
     myLinkedList.remove(3);
    myLinkedList.display();

}

顺序表和链表的区别

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值