数据结构之单链表基本操作

简介: 数据结构之单链表基本操作

一、接口定义

还是和之前的顺序表一样,定义一个接口。后续通过链表类去实现这个定义的接口。

interface SingleLinkedList {
    //头插法
    void addFirst(int data);
    //尾插法
    void addLast(int data);
    //任意位置插入,第一个数据节点为0号下标
    void addIndex(int index,int data);
    //查找是否包含关键字key是否在单链表当中
    boolean contains(int key);
    //删除第一次出现关键字为key的节点
    void remove(int key);
    //删除所有值为key的节点
     void removeAllKey(int key);
    //得到单链表的长度
     int size();
     void clear();
     void display();
}

二、类定义

定义一个链表类,它是由各个节点构成的,因此还需要在链表类内定义一个关于节点的内部类。代码如下:

public class MyLinkedList implements SingleLinkedList {
    class LinkNode {
        public int val;
        public LinkNode next;
        public LinkNode(int val) {
            this.val = val;
        }
    }
    public LinkNode head;
}

三、方法实现

3.1创建单链表(初始化创建)

每次通过LinkNode类定义的节点去new一个新的节点并通过构造函数设置初始值,节点定义完成后,通过各个节点的next域把各个节点之间联系起来,便成功创建了一个单链表。

    public void creatLinkedList() {
        LinkNode node1 = new LinkNode(12);
        LinkNode node2 = new LinkNode(23);
        LinkNode node3 = new LinkNode(34);
        LinkNode node4 = new LinkNode(45);
        LinkNode node5 = new LinkNode(56);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        this.head = node1;
    }

3.2头插法插入节点

    //头插法
    public void addFirst(int data) {
        LinkNode newnode = new LinkNode(data);
        if (this.head == null) {
            this.head = newnode;
        } else {
            newnode.next = this.head;
            this.head = newnode;
        }
    }

3.3尾插法插入节点

尾插法插入节点时,首先要找到单链表的最后一个节点,再去插入

  • 注意,找到单链表的最后一个节点,在while循环里面的控制条件是:cur.next!=null,而不是cur!=null,这一点要切记!!!在我们刷题的时候,很多情况下都要去遍历找节点,因此一定要注意。(cur是一个引用,从head开始遍历)
  • 下图是while(cur.next!=null),循环条件结束的时候,cur所指向的位置:>

image.png

  • 下图是while(cur!=null),循环条件结束的时候,cur所指向的位置:>

image.png

    public void addLast(int data) {
        LinkNode newnode = new LinkNode(data);
        if (this.head == null) {
            this.head = newnode;
            return;
        }
        LinkNode cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = newnode;
    }

3.4指定位置插入节点

在指定位置插入,首先要判断插入位置是否合法。其次,若是在头节点插入,调用头插法即可,若是在尾节点插入,调用尾插法即可。然后,就需要找到指定的位置,此时应该找的是指定位置的前驱节点,通过指定位置的前驱节点的next域指向要插入的节点即可。当然在执行这一步骤之前,我们还需要先把前驱节点的next域所指向的节点交给要插入的节点的next域。

    public void addIndex(int index, int data) {
        if (index < 0 || index > size()) {
            System.out.println("插入位置不合法:>" + index);
            return;
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        LinkNode cur = this.head;
        LinkNode newnode = new LinkNode(data);
        for (int i = 0; i < index - 1; i++) {
            cur = cur.next;
        }
        newnode.next = cur.next;
        cur.next = newnode;
    }

3.5判断节点是否包含在链表中

只需遍历链表,比较节点的值是否和要判断节点的值相等即可。

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

3.6删除值为key的节点

要先找到值为key的节点的前驱节点

    private LinkNode findPrev(int key) {
        LinkNode cur = this.head;
        while ((cur.next != null)) {
            if (cur.next.val == key) {
                return cur;
            }
            cur = cur.next;
        }
        return cur;
    }

以下图为例,假设删除34:>image.png

    public void remove(int key) {
        if (this.head == null) {
            System.out.println("链表为空,无法删除!!!");
            return;
        }
        if (this.head.val == key) {
            this.head = this.head.next;
            return;
        }
/*        while(cur.next!=null){
            //找到要删除节点的前驱
            if(cur.next.val==key){
                LinkNode del=cur.next;
                cur.next=del.next;
                return;
            }else {
                cur=cur.next;
            }
        }*/
        LinkNode prev = findPrev(key);
        if (prev == null) {
            System.out.println("无要删除的数字:>" + key);
            return;
        }
        LinkNode del = prev.next;
        prev.next=del.next;
    }

3.7删除所有值为key的节点

方法是通过双指针来解决:>

假设删除值为23的所有节点。image.png

cur往前走,发现值为23的节点,进行删除操作:>

删除之后,prev指向了23的下一个节点。

image.png

删除完成后,prev不动,cur继续往后遍历:>

image.png

当cur这个引用所指向的节点的值不是23是,prev也要继续往前挪:>

image.png

如此进行下去,即可删除所有值为23的节点。

下面是实现代码:>

    public void removeAllKey(int key) {
        if (this.head == null) {
            System.out.println("链表为空!");
            return;
        }
        LinkNode prev = head;
        LinkNode cur = head.next;
        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;
        }
    }

3.8得到链表长度

很简单,只需通过一个引用遍历即可。如果引用所指的对象不是空,那么计数器+1。

    public int size() {
        LinkNode cur = this.head;
        int count = 0;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

3.9清空链表

    public void clear() {
        LinkNode cur = this.head;
        while (cur != null) {
            LinkNode curNext = cur.next;
            cur.next = null;
            cur = curNext;
        }
        head.next = null;
    }

3.10显示链表(打印)

    public void display(LinkNode newhead) {
        LinkNode cur = newhead;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }
目录
相关文章
|
13天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
32 5
|
1月前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
62 4
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
40 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
2月前
|
存储
[数据结构] -- 单链表
[数据结构] -- 单链表
26 1
|
2月前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
26 7
|
2月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
26 3
|
2月前
|
算法 Java
数据结构与算法学习五:双链表的增、删、改、查
双链表的增、删、改、查操作及其Java实现,并通过实例演示了双向链表的优势和应用。
20 0
数据结构与算法学习五:双链表的增、删、改、查
|
1月前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
43 0