我们来手动实现一下不带头结点的单链表
先把链表的一个节点定义出来
class Node {
int data;
Node next;
public Node(int data) {
this.data = data;
this.next = null;
}
}
接着我们来实现一些接口
//头插法
public void addFirst(int data) {}
在头插之前呢,先判断整个链表是不是空的,也就是this.head == null如果是这样,那就直接把头节点的引用改为此节点,否则进行头插的时候,先让要插入的节点的next指向头节点,然后把头节点变为此节点
//尾插法
public void addLast(int data) {}
在尾插之前呢,先判断整个链表是不是空的,也就是this.head == null如果是这样,那就直接把头节点的引用改为此节点,否则进行尾插的时候,要找到最后一个节点,然后把此节点链在后面
//查找index位置的前一个节点
public Node searchIndex(int index) {}
查找index的前一个节点,那只需要从头节点移动index-1次就找到了,同时也要对index进行合法性判断
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data) {}
任意位置插入的时候,如果这个index = 0,那么就是头插;如果index = this.size(),那么就是尾插;否则就要找到index的前一个结点进行插入,让当前节点的next指向perv.next;然后prev.next=此节点
//链表的长度
public int size() {}
链表长度就没啥好说的,直接遍历一遍,节点为null就结束
//查找是否包含关键字key在单链表中
public boolean contains(int key) {}
contains也是将链表遍历,如果node.data == key;返回true,否则返回false
//查找关键字key的前驱
public Node findPrev(int key) {}
定义一个prev节点从头开始遍历,循环的时候,条件是prev.next != null,因为最后一个节点的next是null,循环体就是比对prev.next.data == key,如果等于,返回prev,循环结束后还没有找到就return false
//删除第一次出现关键字为key的节点
public void romove(int key) {}
如果链表为空就说明里面没有元素,那就更不可能删除其中任意一个元素;如果要删除的是头节点,那就不用找先驱;如果不是头节点,找到key的先驱,然后prev.next就是要删除的del节点,让prev.next = del.next,就完成删除了
//删除所有节点为key的节点
public void romoveAllKey(int key) {}
首先我们要明确一个思路,如果要删除的节点是头节点,那我们不能先删除头节点,如果先删除头节点,要是头节点后面紧跟了一个还需要删除的,那就出bug了,所以我们先把除了头节点以外的删除干净,然后再看要不要删除头节点。删除后面的节点时,定义两个节点,prev,cur(代表要删除的节点),初始化的时候,prev指向头节点,Node prev= this.head; cur指向头结点的下一个,Node cur = this.head.next; 看cur.data等不等于key,如果等于key,进行删除prev.next = cur.next; 然后cur后移,防止是连续的要删除 cur = cur.next; cur为空就删除了除头节点之外的。执行完之后,判断头结点。
//打印单链表
public void display() {}
遍历单链表,输出每一个节点的data即可
//释放内存
public void clear(){}
当一个对象没有人引用的时候,就会被jvm回收掉,所以我们把this.head = null;没有人引用头节点,那头节点就被回收了;回收了以后,头节点的下一个节点也没有人引用,也被回收掉;以此类推…整个链表被clear
下面是具体的实现代码:
package MyLinkedList;
/**
* @author PineappleSnow
* @version 1.0
* @date 2020/4/24 13:17
*/
class Node {
int data;
Node next;
public Node(int data) {
this.data = data;
this.next = null;
}