ArrayList的缺陷
在上一篇博客中,小编已经较为详细得给大家介绍了ArrayList这个结构了。但是ArrayList存在一些缺陷:由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。
因此:java集合中又引入了LinkedList,即链表结构
链表
链表的概念及结构
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
双向 单向、带头 不带头、循环 不循环
我们主要学习:单向不带头非循环、双向不带头非循环
链表的实现
这里就是自己在写一些链表的方法的时候,自己动手实现一下,感受一下这个链表的内部结构。
代码展示:
package LinkedList;
public class MySingleList {
// 这里提供一个内部类
static class ListNode{
public int val; //节点的值域
public ListNode next; // 下一个节点的地址
// 这里提供一个构造方法
public ListNode(int val){
this.val = val;
}
}
public ListNode head; // 表示当前链表的头节点
/**
* 提供一个方法进行链表的初始化
*/
public void createList(){
ListNode node1 = new ListNode(12);
ListNode node2 = new ListNode(34);
ListNode node3 = new ListNode(45);
ListNode node4 = new ListNode(56);
ListNode node5 = new ListNode(67);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
this.head = node1;
}
/**
* 下面是一个方法的实现【其实就是增删改查】
*/
//头插法
public void addFirst(int data){
ListNode node = new ListNode(data);
// // 要考虑列表为空的情况
// if (head == null){
// head = node;
// }
node.next = head;
head = node;
}
//尾插法
public void addLast(int data){
ListNode node = new ListNode(data);
// 要考虑列表为空的情况
if (head == null){
head = node;
return;
}
ListNode curhead = head;
while (curhead.next != null){
curhead = curhead.next;
}
curhead.next = node;
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
ListNode curhead = head;
if (index < 0 || index > size()) {
System.out.println("您提供的index不合法!");
return;
}
ListNode node = new ListNode(data);
// 处理空链表情况
if (head == null) {
if (index == 0) {
head = node;
System.out.println("您的列表为空! 直接插入到第一个位置");
} else {
System.out.println("链表为空,index > 0 无效!");
}
return;
}
if (index == 0){
addFirst(data);
return;
}
for (int i = 0; i < index-1; i++) {
curhead = curhead.next;
}
node.next = curhead.next;
curhead.next = node;
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
// 就默认列表为空就是没有
ListNode curhead = head;
while (curhead!=null){
if (curhead.val == key){
return true;
}
curhead = curhead.next;
}
return false;
}
//删除第一次出现关键字为key的节点
public void remove(int key){
if (head == null) { // 处理空链表
return;
}
// 处理删除头节点的情况
if (head.val == key) {
head = head.next;
return;
}
ListNode cur = head;
while (cur.next != null) { // 遍历链表
if (cur.next.val == key) {
cur.next = cur.next.next; // 删除当前匹配的节点
return; // 只删除第一个匹配项
}
cur = cur.next;
}
}
//删除所有值为key的节点
public void removeAllKey(int key){
if (head == null) { // 处理空链表
return;
}
// 处理删除所有头节点为 key 的情况
while (head != null && head.val == key) {
head = head.next;
}
// 处理删除中间或尾部的 key
ListNode cur = head;
while (cur != null && cur.next != null) {
if (cur.next.val == key) {
cur.next = cur.next.next; // 删除当前匹配的节点
} else {
cur = cur.next; // 只有当 cur.next 不是 key 时才移动
}
}
}
//得到单链表的长度
public int size(){
int ListSize = 0;
ListNode curhead = head;
// 来一个语句判断一下链表是否为空
while (curhead != null){
ListSize++;
curhead = curhead.next;
}
return ListSize; // 如果长度为0【即为空列表即返回这个,告诉用户这是一个空的列表】
}
// 清空所有链表
public void clear() {
this.head = null;
}
// 展示所有列表的数据
public void display() {
// 进来先判断一下链表是否为空
if (head == null){
System.out.println("该列表为空!");
return;
}
ListNode curhead = head;
while (curhead!=null){
System.out.print(curhead.val+" ");
curhead = curhead.next;
}
System.out.println();
}
}
注:小编这里的代码并不是最优的,只是起一个参考的作用。
测试代码:
package LinkedList;
public class Test {
public static void main(String[] args) {
MySingleList mySingleList = new MySingleList();
mySingleList.createList(); // 先把这个初始列表创建出来
// 将列表全部展现出来
mySingleList.display();
// 得到单链表的长度
int length = mySingleList.size();
System.out.println("单链表的长度为:"+length);
// 进行头插
mySingleList.addFirst(99);
mySingleList.display();
// 进行尾插
mySingleList.addLast(520);
mySingleList.display();
// 任意位置插入
mySingleList.addIndex(0, 1314);
mySingleList.display();
m