前言
这次文章为大家带来了链表,模拟无头单向非循环链表的实现,希望可以对你有所帮助。😊😊
一、链表
1.链表的概念及结构
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。
- 链表性质
1.链表在逻辑上是连续的。
2.所以物理上可能连续,也可能不连续。(结点一般是从堆上申请出来的,申请的空间按照一定策略分配)
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
- 单向或者双向
- 带头或者不带头
- 循环或者非循环
本文分享的是无头单向非循环链表。
二、模拟链表实现
public class SingleLinkedList {
//定义一个静态内部类,作为链表的结点
static class Node {
int val;
Node next;
public Node(int val) {
this.val = val;
}
}
Node head;//头结点,即第一个结点
//头插法
public void addFirst(int data){
//首先,先new一个新结点
Node node = new Node(data);
//头插,那么插入的这个结点就将变为第一个结点
//所以要先存储旧的头结点
node.next = head;
//然后将类中的头结点更新
head = node;
}
//尾插法
public void addLast(int data){
//首先,先new一个新结点
Node node = new Node(data);
//尾插,即插入的这个结点变为最后一个结点
//此刻要考虑一种情况,如果此时链表当中没有数据,
//那么新结点一定是第一个数据,直接更新头结点即可
if(head == null) {
head = node;
}
//先找到最后一个结点,即next==null的结点
Node cur = head;//不改变类内存储的头结点,防止链表丢失
while(cur.next != null) {
cur = cur.next;
}
//将新结点的地址给末结点的next即可
cur.next = node;
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
//老规矩,要检查位置合法性,
if(index > size()) { //size方法在下面
//如果不合法则抛出异常
throw new SingleLinedListRunException("输入位置不合法");
//异常类的定义也在下面
}
//如果index为0,即首插法,
if(index == 0) {
addFirst(data);
return;
}
//如果index==size()即尾插法
if(index == size()) {
addLast(data);
return;
}
Node node = new Node(data);
Node cur = head;
//如果要将一个结点插入到某个位置,
//那么找到这个位置的前一个结点
//将这个结点的next改为新节点地址即可
for (int i = 0; i < index-1; i++) {
cur = cur.next;
}
//找到前一个结点后
//首先将前一个结点中存储的地址存入新结点中
node.next = cur.next;
//然后将前一个结点的next改为新结点,就完成了插入
cur.next = node;
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
Node cur = head;
//遍历整个链表,找到即返回true
while (cur != null) {
if(cur.val == key) {
return true;
}
cur = cur.next;
}
//走到这一步,即整个链表中不存在key
return false;
}
//删除第一次出现关键字为key的节点
public void remove(int key){
//考虑特殊情况,如果头结点就是要删除的结点呢?
//直接改变类内存储的头结点
if(head.val == key) {
head = head.next;
return;
}
Node cur = head;
//要删除这个结点,只需找到这个结点的前一个结点
while (cur.next != null) {
if(cur.next.val == key) {
break;
}
cur = cur.next;
}
//将前一个结点存储的地址改为要删除结点的后一个结点的地址
cur.next = cur.next.next;
}
//删除所有值为key的节点
public void removeAllKey(int key){
Node cur = head;
//要删除这个结点,只需找到这个结点的前一个结点
while (cur.next != null) {
if(cur.next.val == key) {
//将前一个结点存储的地址改为要删除结点的后一个结点的地址
//思路与上一个方法相同,只不过没有让代码找到一个就停止
cur.next = cur.next.next;
}
cur = cur.next;
}
//此时除头结点外,其他值为key的结点都已经被删除了
//那么现在就要考虑头结点了
if(head.val == key) {
head = head.next;
}
}
//得到单链表的长度
public int size(){
//遍历链表,记录不为空的结点个数
Node cur = head;
int size = 0;
while (cur != null) {
size++;
cur = cur.next;
}
return size;
}
public void clear() {
//可以直接将类内存储的头结点变为null,其他结点,不再被引用,则会被一一回收
head = null;
}
public void display() {
//遍历并打印链表
Node cur = head;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
}
//异常类的定义
public class SingleLinedListRunException extends RuntimeException{
public SingleLinedListRunException(String message) {
super(message);
}
}
总结
以上就是今天要讲的内容,本文简单介绍了链表并模拟实现了无头单向非循环链表,如果对你有所帮助,请帮作者点个赞吧👍。
路漫漫,不止修身也养性。