【数据结构】认识链表和模拟实现单链表(2)

简介: 【数据结构】认识链表和模拟实现单链表

2.3 MyLinkedList类的成员方法

2.3.1 在链表开头插入一个新结点

在链表开头插入一个结点,首先需要根据 data 数据实例化一个结点。然后让这个新结点的 next 指针域存 head 的地址, 这样就让新的结点与后面的结点链接起来了,最后让 head 等于这个新结点,这样这个新结点就变成了第一个结点

//头插法
public void addFirst(int data) {
    Node nodeTmp = new Node(data);
    nodeTmp.next = this.head;
    this.head = nodeTmp;
}

2.3.2 获取链表的最后一个结点

首先 head 不能移动,如果移动第一个结点就会因没有被指向而回收,那么后面结点也就会因为没有被指向而被回收,所以需要创建一个临时的结点类型的变量 src,将 head 指向的结点赋值给它,这样 head 和 src 同时指向了第一个结点,当src 移动到其他结点,第一个结点还是会被 head 所指向。src 通过循环一直等于下一个结点,当 src 存储的结点的 next 为 null 时就为最后一个结点


//获取链表的最后一个结点
private Node lastNode() {
    Node src = this.head;
    while (src.next != null) {
        src = src.next;
    }
    return src;
}

注:这个方法是private修饰所以只能在 MyLinkedList类 中使用


2.3.3 在链表尾部插入一个新的结点

在链表尾部插入一个结点,首先需要这个链表是否为空,如果链表为 null ,尾插一个结点就相当于在链表开头插入一个结点。如果链表不为 null ,尾部插入一个结点就需要根据 data 数据实例化一个结点,然后通 lastNode 方法获取最后一个结点,让最后一个结点的 next 存储新结点的地址即可

//尾插法
public void addLast(int data) {
    if (head == null) {
        addFirst(data);
        return;
    }
    Node nodeTmp = new Node(data);
    Node last = lastNode();
    last.next = nodeTmp;
}

2.3.4  返回指定位置的前一个结点

首先判断位置是否合法,如果不合法直接返回 null ,否则用一个临时结点变量等于 head 指向的结点,然后通过循环 index - 1 次而找的指定位置的前一个结点


//返回指定位置的前一个结点
private Node prevNode(int index) {
    if (index > size() || index < 0) {
        return null;
    }
    Node src = this.head;
    while(index != 1) {
        src = src.next;
        index--;
    }
    return src;
}

2.3.5 在链表指定位置插入一个新结点

第一步判断指定位置是否合法,如果不合法直接返回 false。否则进入第二步判断插入的位置是否为第一个结点位置,如果是就直接采用头插法在链表的开头插入一个结点。否则进入第三步判断插入的位置是否为最后一个结点的下一个位置,如果是就直接采用尾插法在链表的尾部插入一个结点。否则就在实例化一个 data 数据结点,调用 preNode 方法获取指定位置的前一个结点,在用一个临时变量去存储前一个结点的后一个结点,让前一个结点的 next 存储这个新的结点地址,再让这个新的结点的 next 存储后一个结点地址即可




//任意位置插入,第一个数据结点为0号下标
public boolean addIndex(int index,int data) {
    if (index > size() || index < 0) {
        return false;
    } else if (index == 0) {
        addFirst(data);
    } else if (index == size()) {
        addLast(data);
    } else {
        Node nodeTmp = new Node(data);
        Node prev = prevNode(index);//指定位置前一个结点
        Node tmp = prev.next;//指定位置的结点
        prev.next = nodeTmp;
        nodeTmp.next = tmp;
    }
    return true;
}


注:if...else if...else if...else...这种多判断只会执行其中的一个


2.3.6  判断是否需要删除第一个结点

判断数据 key 是否与第一个结点数据域中的数据相同,如果相同则让head等于head.next,这样head就指向了下一个结点,也就删除了第一个结点


//判断第一个结点是否是指定的结点,如果是则删除第一个结点
private boolean judgeFistNode(int key) {
    if (key == this.head.data) {
        this.head = this.head.next;
        return true;
    }
    return false;
}

2.3.6 删除第一次出现的指定数据的结点

首先判断这个链表是否为 null,否则就判断指定数据的结点是否为链表的第一个结点,否则就通过两个结点变量去找这个数据结点以及它的前一个结点,找到之后让它的前一个结点的 next 存储它后结点的地址然后直接return,因为只删除第一次输出的指定数据的结点。如果遍历完都没有找到这个数据结点则没有这个数据结点


//删除第一次出现关键字为key的节点
public void remove(int key) {
    if (this.head == null) {
        return;
    }
    boolean judge = judgeFistNode(key);
    if (judge == true) {
        return;
    }
    Node src = this.head;
    Node slow = this.head;
    while (src != null) {
        if (src.data != key) {
            slow = src;
            src = src.next;
        } else {
            slow.next = src.next;
            return;
        }
    }
}


2.3.7 删除所有指定数据的结点

首先判断这个链表是否为 null, 否则就通过两个结点变量去找这个数据结点以及它的前一个结点,找到之后让它的前一个结点的 next 存储它后结点的地址,一直遍历完,因为要删除所有指定数据的结点。遍历完后在判断第一个结点是否为空,也就相当于如果第一个结点是要删除的结点,先不管它,先删后面的在删第一个结点


//删除所有值为key的节点
public void removeAllKey(int key) {
    if (this.head == null) {
        return;
    }
    Node src = this.head;
    Node slow = this.head;
    while (src != null) {
        if (src.data != key) {
            slow = src;
            src = src.next;
        } else {
            slow.next = src.next;
            src = src.next;
        }
    }
    judgeFistNode(key);
}


2.3.8 查找链表中是否有指定的数据

直接将这个链表遍历一遍,如果有直接返回 true,否则返回 false


//查找是否包含关键字key是否在单链表当中
public boolean contains(int key) {
    Node src = this.head;
    while (src != null) {
        if (src.data == key) {
            return true;
        }
        src = src.next;
    }
    return false;
}

2.3.9 获取链表的长度

直接将这个链表遍历一遍用一个整型变量计数即可


//得到单链表的长度
public int size() {
    Node src = this.head;
    int count = 0;
    while (src != null) {
        count++;
        src = src.next;
    }
    return count;
}

2.3.10 打印链表

首先判断这个链表是否为 null ,如果为空直接打印 null。否则将这个链表遍历一遍,打印每个结点数据域中的数据

//打印链表
public void display() {
    if (this.head == null) {
        System.out.print("null");
    }
    Node src = head;
    while (src != null) {
        System.out.print(src.data + " ");
        src  = src.next;
    }
    System.out.println();
}

2.3.11 清空链表

直接让 head 指向 null,这样第一个结点就没有被指向了,会直接被编译器回收。第一个结点被回收了,第二个结点也就没有被指向了也会被回收,依次如此,直到将整个链表全部回收


//清除链表
public void clear() {
    this.head = null;
}


相关文章
|
3天前
|
存储
数据结构第二课 -----线性表之单向链表
数据结构第二课 -----线性表之单向链表
|
2天前
|
存储
数据结构链表详解(不仅顺序表可以,我链表也可以)
数据结构链表详解(不仅顺序表可以,我链表也可以)
11 0
|
3天前
特殊链表(循环单链表,循环双链表,静态链表)
特殊链表(循环单链表,循环双链表,静态链表)
13 3
|
3天前
|
存储 算法 Java
数据结构与算法 数组和链表
数据结构与算法 数组和链表
12 0
|
3天前
|
存储 Java
深入浅出数据结构之链表
深入浅出数据结构之链表
|
3天前
|
C++
数据结构(循环单链表
数据结构(循环单链表
12 2
|
3天前
|
C++
数据结构(双链表
数据结构(双链表
11 1
|
3天前
|
C++
数据结构(单链表
数据结构(单链表
9 0
|
3天前
|
存储 缓存
[数据结构]~双向+循环链表从(0~1)
[数据结构]~双向+循环链表从(0~1)
|
3天前
|
存储
[数据结构]单链表(从0->1)
[数据结构]单链表(从0->1)