线性表的链式存储——链表

简介: 线性表的链式存储——链表

1.概念

       链式存储是常用的动态存储方式,相对于顺序表,可以更好的任意插入与删除,而采用链式存储的结构叫做链表。

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

       从链接方式的角度:链表分为单链表、双链表及循环链表;

       从实现方式的角度:链表分为动态链表和静态链表;


2.链表

2.1 单链表概念及结构

概念:

       单链表是通过一个一个结点进行连接,而链表并不像顺序表一样存储的是一组地址连续的存储单元,而是非连续的。因此,链表中的结点不仅需要存储自己的数据元素值(数据域),还需要存储下一个结点的地址(指针域)。


 结构:

634b7e4ca37a423f835746c6ebb8c0a6.png

  单链表的每个结点的地址都存储在其前驱结点的指针域中,因此第一个结点无前驱,这个时候我们可以设置一个头指针Head指向第一个结点。而最后一个结点后面没有结点,所以最后一个结点指针域为空(Null)


单链表结构:

96966e70fe304bd6b3e1f5f8c010666d.png


2.2双链表的概念及结构

概念:

       每个结点相对与单链表多了一个指针域,其它与单链表基本相同。

结构:

20a1423dffd44c35a9dae4512b159068.png

6bdde687069440be8825b211eb4f70ba.png


2.3 循环链表

概念:

       循环链表是建立在单链表和双链表的基础上,将头尾相连,形成一个环,这就是循环链表,可分为:循环单链表、循环双链表。

8cc6f475a0a040fdaf3eb9ccd318ae66.png



d0c5661a614a465dae13978deda1b605.png


3.链表的具体使用

方法 解释
add(E e) 尾插 e

add(int i, E e) 

把e插在i位置
addAll(Collection<? extends E> c) 尾插c
addFirst(E e) 头插e
remove(int i) 删除i坐标元素
remove(int i) 删除i坐标元素
get(int i) 获得i坐标元素

set(int i , E e) 将i坐标元素换为e
clear() 清空
contains(object o ) 判定o是否存在
indexOf(object  o) 返回第一个o所在位置的下标

lastIndexOf(object o) 返回最后一个o下标
subList(int f, int t) 截取f坐标到t坐标list


代码实现:

public class Test1 {
    public static void main(String[] args) {
        System.out.println(list.add(1));//尾插1,Boolean
        list.addFirst(2);//头插2
        System.out.println(list);
        list.addLast(3);//尾插3
        System.out.println(list);
        list.add(1,4);//1坐标插入4
        System.out.println(list);
        list.remove(2);//删除2坐标元素
        System.out.println(list);
        System.out.println(list.get(2));//获得2坐标元素
        System.out.println(list);
        list.set(1,3);//将1坐标元素改为3
        System.out.println(list);
        System.out.println(list.contains(3));//是否含5
        System.out.println(list.contains(6));//是否含6
        System.out.println(list.indexOf(3));//第一个3的下标
        System.out.println(list.lastIndexOf(3));//最后一个3的下标
        System.out.println(list.subList(0,1));//截取[0,1)的list,前闭后开
        System.out.println(list.isEmpty());//list中是否有元素
        list.clear();//清空
        System.out.println(list.isEmpty());
    }
}


运行结果:

true
[2, 1]
[2, 1, 3]
[2, 4, 1, 3]
[2, 4, 3]
3
[2, 4, 3]
[2, 3, 3]
true
false
1
2
[2]
false
true


4.自己实现链表及方法:

注意:

       上面这些方法的实现,我们可以直接用,但是我们也可以创建自己的链表,实现自己的方法,让我们更好的理解,提升我们的代码能力。

       代码的实现我放在了下面,但是最好自己实现一遍。


双链表:

public class MyLinkedList {
    static class ListNode{
        public int val;
        public ListNode prev;
        public ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
    public ListNode last;
    //头插法
    public void addFirst(int data){
        ListNode listNode = new ListNode(data);
        if (head == null){
            head = listNode;
            last = listNode;
        }else{
            head.prev = listNode;
            listNode.next = head;
            head = listNode;
        }
    }
    //尾插法
    public void addLast(int data){
        ListNode listNode = new ListNode(data);
        if(last == null){
            last = listNode;
            head = listNode;
        }else{
            last.next = listNode;
            listNode.prev = last;
            last = listNode;
        }
    }
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        ListNode listNode = new ListNode(data);
        if(index < 0 || index > size()){
            System.out.println("不合法");
            return;
        }
        if(index == 0){
            addFirst(data);
            return;
        }
        if (index == size()){
            addLast(data);
            return;
        }
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        listNode.next = cur;
        cur.prev.next = listNode;
        listNode.prev = cur.prev;
        cur.prev = listNode;
    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        ListNode cur = head;
        while (cur != null){
            if(cur.val == key){
                return true;
            }
        }
        return false;
    }
    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur = head;
        while (cur != null){
            if(cur.val == key){
                if(cur == head){
                    head = head.next;
                }else{
                    if (cur.next == null) {
                        cur.prev.next = null;
                        last = cur.prev;
                    }else{
                        cur.prev.next = cur.next;
                        cur.next.prev = cur.prev;
                    }
                }
                return;
            }else{
                cur = cur.next;
            }
        }
        System.out.println("没有这个节点");
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        ListNode cur = head;
        while (cur != null){
            if(cur.val == key){
                if(cur == head){
                    head = head.next;
                }else{
                    if (cur.next == null) {
                        cur.prev.next = null;
                        last = cur.prev;
                    }else{
                        cur.prev.next = cur.next;
                        cur.next.prev = cur.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }
    //得到单链表的长度
    public int size(){
        int count = 0;
        ListNode cur = head;
        while (cur != null){
            count++;
            cur = cur.next;
        }
        return count;
    }
    public void display(){
        ListNode cur = head;
        while (cur != null){
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }
    public void clear(){
        head = null;
    }
}


单链表:

public class SingleLinkedList {
    class ListNode{
        public int val;
        public ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
    public void createNode(){
        ListNode listNode1 = new ListNode(12);
        ListNode listNode2 = new ListNode(23);
        ListNode listNode3 = new ListNode(34);
        ListNode listNode4 = new ListNode(45);
        ListNode listNode5 = new ListNode(45);
        head = listNode1;
        listNode1.next = listNode2;
        listNode2.next = listNode3;
        listNode3.next = listNode4;
        listNode4.next = listNode5;
    }
    public ListNode head;
    //打印
    public void show(){
        ListNode cur = head;
        for (int i = 0; i < size(); i++) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }
    //长度
    public int size(){
        ListNode cur = head;
        int count = 0;
        while(cur != null){
            cur = cur.next;
            count++;
        }
        return count;
    }
    //查找
    public boolean contains(int key){
        ListNode cur = head;
        if(cur == null){
            return false;
        }
        while (cur.val != key){
            if(cur.next == null){
                return false;
            }
            cur = cur.next;
        }
        return true;
    }
    //头插
    public void addFirst(int data){
        ListNode newNode = new ListNode(data);
        newNode.next = head;
        head = newNode;
    }
    //尾插
    public void addLast(int data){
        ListNode newNode = new ListNode(data);
        ListNode cur = head;
        while (cur.next != null){
            cur = cur.next;
        }
        cur.next = newNode;
    }
    //随意插
    public void addIndex(int index,int data){
        ListNode cur = head;
        ListNode newNode = new ListNode(data);
        if(index == 0){
            addFirst(data);
            return;
        }
        if(index < 0 || index > size() || cur == null){
            throw new IndexOutOfBounds("数组不合法,越界: " + index);
        }
        if(index == size()){
            addLast(data);
            return;
        }
        for (int i = 1; i < index; i++) {
            cur = cur.next;
        }
        newNode.next = cur.next;
        cur.next = newNode;
    }
    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur = head;
        ListNode pver = head;
        if(cur == null){
            System.out.println("链表无节点");
            return;
        }
        if(cur.val == key){
            head = head.next;
        }
        while(cur.val != key){
            if(cur.next == null){
                System.out.println("无此节点");
                return;
            }
            pver = cur;
            cur = cur.next;
        }
        if(cur.val == key){
            pver.next = cur.next;
            return;
        }
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        if(head == null) {
            return;
        }
        ListNode cur = head.next;
        ListNode prev = head;
        while (cur != null) {
            if(cur.val == key) {
                prev.next = cur.next;
                cur = cur.next;
            }else {
                prev = cur;
                cur = cur.next;
            }
        }
        if(head.val ==  key) {
            head = head.next;
        }
    }
    //清除所有数据
    public void clear(){
        head = null;
    }
}


目录
相关文章
|
5月前
|
算法
数据结构和算法学习记录——线性表之双向链表(上)-结点类型定义、初始化函数、创建新结点函数、尾插函数、打印函数、尾删函数
数据结构和算法学习记录——线性表之双向链表(上)-结点类型定义、初始化函数、创建新结点函数、尾插函数、打印函数、尾删函数
48 0
|
6月前
|
存储
数据结构第二课 -----线性表之单向链表
数据结构第二课 -----线性表之单向链表
|
5月前
|
算法
数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数
数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数
30 0
|
5月前
|
算法
数据结构和算法学习记录——线性表之单链表(下)-头插函数、尾删函数、头删函数、查找函数、pos位置插入&删除数据、单链表销毁
数据结构和算法学习记录——线性表之单链表(下)-头插函数、尾删函数、头删函数、查找函数、pos位置插入&删除数据、单链表销毁
62 0
|
5月前
|
存储 算法
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
39 0
|
6月前
|
存储 缓存 算法
【数据结构】线性表----链表详解
【数据结构】线性表----链表详解
96 0
|
6月前
|
存储
数据结构第三课 -----线性表之双向链表
数据结构第三课 -----线性表之双向链表
|
5月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
5月前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
5月前
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
56 2