目录
- 1. 链表相关概念
- 2. 功能实现
- 2.1 整体框架
- 2.2 增加
- addFirst
- addLast
- addIndex
- 2.3 删除
- 2.3.1 remove
- 2.3.2 removeall
- 2.4 查找
- contains
- 2.4 修改
- 2.4.1 modify
- 2.4.2 modifyAll
- 3. 全部代码
1. 链表相关概念
老铁们好!今天我们要学习一种新的数据结构:链表。链表是一种逻辑上连续,物理上不连续的一种数据结构,它由一个一个的结点构成,每个结点包含数据和下一个结点的地址,如图。由于最后一个结点没有后续的结点,所以next为null
链表有很多种结构:单向、双向、循环、非循环、有头、无头。链表结构有很多,但是我们只学习两种:无头单向非循环链表(最简单的)和无头双向非循环链表(Java集合框架中的LinkedList的底层),今天我们先实现最简单的无头单向非循环链表。
2. 功能实现
2.1 整体框架
定义MySignalList泛型类,表示一个链表,定义静态内部类ListNode表示链表的结点,内部类中val表示数据,next表示下一个结点的地址,同时提供ListNode构造方法,初始化val,head表示链表的第一个结点,此外,MySignalList类中还有若干的增删查改等功能的方法
public class MySignalList<T> {
static class ListNode {
public Object val;
public ListNode next;
public ListNode(Object val) {
this.val = val;
}
}
public ListNode head;
//........
//若干方法
}
接下来我们介绍相关的功能的实现
2.2 增加
addFirst
头插,将申请的新的结点的next指向head,再更新head的值即可
public void addFirst(T val) {
ListNode newNode = new ListNode(val);
newNode.next = head;
head = newNode;
}
addLast
尾插,如果链表没有元素,head为空,则将申请的新结点赋值给head即可,如果链表不为空,需要找到最后一个结点(尾结点),将尾结点的next指向新的结点即可
public void addLast(T val) {
ListNode newNode = new ListNode(val);
if (head == null) {
//如果链表为空
head = newNode;
return;
}
//找尾
ListNode tail = head;
while (tail.next != null) {
tail = tail.next;
}
tail.next = newNode;
}
addIndex
在Index位置插入数据,首先需要判断Index的合法性,我们定义一个异常类IndexNotLegalException:
public class IndexNotLegalException extends RuntimeException {
public IndexNotLegalException() {
super();
}
public IndexNotLegalException(String s) {
super(s);
}
}
如果Index小于0或者Index大于链表的长度size,抛出异常,如果Index等于0,表示头插;如果Index等于链表长度size,表示尾插,头插、尾插直接调用之前写的方法即可
获取链表长度:
public int size() {
int size = 0;
ListNode cur = head;
while (cur != null) {
cur = cur.next;
size++;
}
return size;
}
排查了Index的合法性后,要在Index位置插入数据,先要找到Index前一个位置(定义临时结点cur,循环往后走Index-1步),找到之后,让新的结点绑定后面的链表,然后将Index前一个结点的next指向新的结点,如图
public void addIndex(int Index, T val) {
//判断Index的合法性
try {
if (Index < 0 || Index > size()) {
throw new IndexNotLegalException("Index不合法");
}
} catch (IndexNotLegalException e) {
e.printStackTrace();
}
if (Index == 0) {
addFirst(val);
return;
}
if (Index == size()) {
addLast(val);
return;
}
ListNode newNode = new ListNode(val);
ListNode cur = head;
for (int i = 0; i < Index - 1; i++) {
cur = cur.next;
}
//cur在index前面
newNode.next = cur.next;
cur.next = newNode;
}
2.3 删除
2.3.1 remove
删除第一个值为key的结点,如果链表为空直接return。
删除的逻辑:循环遍历链表,使用equals方法比较结点的值是否与key相等,定义前驱结点prev记录前一个结点的位置,定义当前结点cur用于遍历链表。如果找到了,让prev结点的next指向当前结点的下一个结点
//删除第一次出现的key
public void remove(T key) {
if (head == null) {
return;
}
ListNode cur = head;
ListNode prev = null;
while (cur != null) {
if (cur.val.equals(key)) {
if (prev == null) {
//如果第一个结点的值是key,让head往后走,然后return
head = head.next;
return;
}
prev.next = cur.next;
return;
}
prev = cur;
cur = cur.next;
}
}
2.3.2 removeall
删除所有值为key的结点,与remove逻辑一样,remove删除之后就return了,removeall删除之后不需要return,继续执行之前的操作即可
//删除所有的key
public void removeAll(T key) {
if (head == null) {
return;
}
//如果前半部分都是key,直接让head往后走,如果head为空了就return
while (head.val.equals(key)) {
head = head.next;
if (head == null) {
return;
}
}
ListNode cur = head.next;
ListNode prev = head;
while (cur != null) {
if (cur.val.equals(key)) {
prev.next = cur.next;
} else {
prev = cur;
}
cur = cur.next;
}
}
2.4 查找
contains
判断链表中是否包含某个值,如果包含返回true,否则返回false
循环遍历链表,使用equals方法比较值是否相等,如果有相等的结点返回true
//是否包含val
public boolean contains(T val) {
if (head == null) {
//链表为空,返回false
return false;
}
ListNode cur = head;
while (cur != null) {
if (cur.val.equals(val)) {
return true;
}
cur = cur.next;
}
return false;
}
2.4 修改
2.4.1 modify
修改第一个值为oldVal的结点,将其改为newVal
循环遍历链表,找到了该结点就将val修改
//修改第一次出现的oldVal,将它改为newVal
public void modify(T oldVal, T newVal) {
if (head == null) {
return;
}
ListNode cur = head;
while (cur != null) {
if (cur.val.equals(oldVal)) {
cur.val = newVal;
return;
}
cur = cur.next;
}
}
2.4.2 modifyAll
修改所有值为结点oldVal,将其改为newVal
循环链表,直到修改完所有的结点为止
//修改所有的oldVal,将它改为newVal
public void modifyAll(T oldVal, T newVal) {
if (head == null) {
return;
}
ListNode cur = head;
while (cur != null) {
if (cur.val.equals(oldVal)) {
cur.val = newVal;
}
cur = cur.next;
}
}
3. 全部代码
//单链表
public class MySignalList<T> {
static class ListNode {
public Object val;
public ListNode next;
public ListNode(Object val) {
this.val = val;
}
}
public ListNode head;
//头插
public void addFirst(T val) {
ListNode newNode = buyNode(val);
newNode.next = head;
head = newNode;
}
//尾插
public void addLast(T val) {
ListNode newNode = buyNode(val);
if (head == null) {
head = newNode;
return;
}
//找尾
ListNode tail = head;
while (tail.next != null) {
tail = tail.next;
}
tail.next = newNode;
}
//在Index位置插入
public void addIndex(int Index, T val) {
//判断Index的合法性
try {
if (Index < 0 || Index > size()) {
throw new IndexNotLegalException("Index不合法");
}
} catch (IndexNotLegalException e) {
e.printStackTrace();
}
if (Index == 0) {
addFirst(val);
return;
}
if (Index == size()) {
addLast(val);
return;
}
ListNode newNode = buyNode(val);
ListNode cur = head;
for (int i = 0; i < Index - 1; i++) {
cur = cur.next;
}
//cur在index前面
newNode.next = cur.next;
cur.next = newNode;
}
//删除第一次出现的key
public void remove(T key) {
if (head == null) {
return;
}
ListNode cur = head;
ListNode prev = null;
while (cur != null) {
if (cur.val.equals(key)) {
if (prev == null) {
head = head.next;
return;
}
prev.next = cur.next;
return;
}
prev = cur;
cur = cur.next;
}
}
//删除所有的key
public void removeAll(T key) {
if (head == null) {
return;
}
//如果前半部分都是key
while (head.val.equals(key)) {
head = head.next;
if (head == null) {
return;
}
}
ListNode cur = head.next;
ListNode prev = head;
while (cur != null) {
if (cur.val.equals(key)) {
prev.next = cur.next;
} else {
prev = cur;
}
cur = cur.next;
}
}
//是否包含val
public boolean contains(T val) {
if (head == null) {
return false;
}
ListNode cur = head;
while (cur != null) {
if (cur.val.equals(val)) {
return true;
}
cur = cur.next;
}
return false;
}
//返回结点
public ListNode find(T findVal) {
if (head == null) {
return null;
}
ListNode ret = head;
while (ret != null) {
if (ret.val.equals(findVal)) {
return ret;
}
ret = ret.next;
}
return null;
}
//修改第一次出现的oldVal,将它改为newVal
public void modify(T oldVal, T newVal) {
if (head == null) {
return;
}
ListNode cur = head;
while (cur != null) {
if (cur.val.equals(oldVal)) {
cur.val = newVal;
return;
}
cur = cur.next;
}
}
//修改所有的的oldVal,将它改为newVal
public void modifyAll(T oldVal, T newVal) {
if (head == null) {
return;
}
ListNode cur = head;
while (cur != null) {
if (cur.val.equals(oldVal)) {
cur.val = newVal;
}
cur = cur.next;
}
}
public int size() {
int size = 0;
ListNode cur = head;
while (cur != null) {
cur = cur.next;
size++;
}
return size;
}
}
今天的内容就到这里,感谢老铁们的点赞、收藏、评论~❤