【难点】:remove、removeAllKey
package bagfour;
/**
* Created with IntelliJ IDEA.
* Description:
* User: tangyuxiu
* Date: 2024-08-20
* Time: 20:58
*/
public interface IList {
//头插法
void addFirst(E data);
//尾插法
void addLast(E data);
//任意位置插入,第一个数据节点为0号下标
void addIndex(int pos,E data);
//查找是否包含关键字key是否在单链表当中
boolean contains(E key);
//删除第一次出现关键字为key的节点
void remove(E key);
//删除所有值为key的节点
void removeAllKey(E key);
//得到单链表的长度
int size();
void clear();
void display();
}
package bagfour;
/**
* Created with IntelliJ IDEA.
* Description:
* User: tangyuxiu
* Date: 2024-08-20
* Time: 20:58
*/
public class MyLinkedList implements IList {
/* 使用内部类来定义链表节点 */
private static class ListNode {
E val;
ListNode next;//默认为null
public ListNode(E val) {
this.val = val;
}
}
private ListNode head;
/* 头插 */
@Override
public void addFirst(E data) {
ListNode newNode = new ListNode<>(data);
this.head.next = this.head;
this.head = newNode;
}
/* 尾插 */
@Override
public void addLast(E data) {
ListNode newNode = new ListNode<>(data);
//1. 如果链表为null
if (this.head == null) {
this.head = newNode;
return;
}
//2. 尾插
ListNode cur = this.head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = newNode;
}
/* 判断add位置是否合法 */
private boolean addIndexIsLegal(int pos) {
if (pos < 0 || pos > this.size()) {
return false;
}
return true;//如果链表为null,且pos位置为0,此时也是合法的
}
/* 任意位置插入 */
@Override
public void addIndex(int pos, E data) {
//1. 判断add位置是否合法
if (!this.addIndexIsLegal(pos)) {
return;
}
//2. pos == 0(链表为null且index=0,也走的这里)
if (pos == 0) {
this.addFirst(data);
return;
}
//3. pos == size()
if (pos == this.size()) {
this.addLast(data);
return;
}
//4. 其他位置
ListNode newNode = new ListNode<>(data);
ListNode cur = this.head;
//寻找pos节点的前一个节点
//【思路】本来想要找到到index下标所指向的节点的,但发现
// 我们要找的其实不是index下标所指向的节点而是要找到它的前一个节点
// 那么我们将cur原本要走的index步,改为走index - 1步即可
for (int i = 0; i < pos - 1; i++) {//这里的问题头插部分已经考虑到了
cur = cur.next;
}
newNode.next = cur.next;
cur.next = newNode;
}
/* 是否存在某元素 */
@Override
public boolean contains(E key) {
ListNode cur = this.head;
while (cur != null) {
if (cur.val.equals(key)) {
return true;
}
cur = cur.next;
}
return false;
}
/* 删除第一次出现关键字为key的节点 */
@Override
public void remove(E key) {
//1. 如果链表为null
if (this.head == null) {
return;
}
//2. 如果key在头节点处
if (this.head.val.equals(key)) {
this.head = this.head.next;
return;
}
//3. 如果key在其他位置
ListNode pre = this.head;
//找到key的前一个节点
while (pre.next != null) {
ListNode del = pre.next;
if (del.val.equals(key)) {
pre.next = del.next;
return;
}
pre = pre.next;
}
}
/* 删除所有值为key的节点 */
@Override
public void removeAllKey(E key) {
//1. 如果链表为null
if (this.head == null) {
return;
}
//2. 其他位置
ListNode pre = this.head;
ListNode del = pre.next;
while (pre.next != null) {
if (del.val.equals(key)) {
pre.next = del.next;
//del = del.next;
} else {
pre = pre.next;
//del = del.next;
}
del = del.next;
}
//3. 如果key在头节点处
if (this.head.val.equals(key)) {
//为什么下行代码不写成pre = pre.next呢?
//答:“正常”的代码中pre,find只是工具,真正的head一直仍然指向的是同一个节点
this.head = this.head.next;
}
}
/* 得到单链表的长度 */
@Override
public int size() {
int count = 0;
ListNode cur = this.head;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
/* 清空链表 */
@Override
public void clear() {
ListNode cur = this.head;
while (cur != null) {
cur.val = null;
cur = cur.next;
}
this.head = null;
}
/* 打印 */
@Override
public void display() {
ListNode cur = this.head;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
}