文章目录
- 1. ArrayList的缺陷
- 2. 链表
- 2.1 链表的概念及结构
- 2.2 链表的实现
- 1.链表的功能
- 2.初始化链表
- 3.实现功能接口
- 3.1头插添加元素
- 3.2尾插法添加新元素
- 3.3找到下标的前驱节点
- 3.4指定位置插入元素
- 3.5指定元素是否存在
- 3.6找到指定元素的前驱节点
- 3.7删除指定节点
- 3.8删除所有元素为key的节点
- 3.9链表的长度
- 3.9清空链表
- 完整代码
1. ArrayList的缺陷
上节课已经熟悉了ArrayList的使用,并且进行了简单模拟实现。通过源码知道,ArrayList底层使用数组来存储元素:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{// ...// 默认容量是10private static final int DEFAULT_CAPACITY = 10;//...// 数组:用来存储元素transient Object[] elementData; // non-private to simplify nested class access// 有效元素个数private int size;public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}
//
}
由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java集合中又引入了LinkedList,即链表结构。
2. 链表
2.1 链表的概念及结构
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
- 单向或者双向
- 带头或者不带头
- 循环或者非循环
虽然有这么多的链表的结构,但是我们重点掌握两种:
无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多
无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表
2.2 链表的实现
1.链表的功能
package mysingleList;public interface IList {void addFirst(int data);//尾插法void addLast(int data);//任意位置插入,第一个数据节点为0号下标void addIndex(int index,int data);//查找是否包含关键字key是否在单链表当中boolean contains(int key);//删除第一次出现关键字为key的节点void remove(int key);//删除所有值为key的节点void removeAllKey(int key);//得到单链表的长度int size();void clear();void display();
}
2.初始化链表
public class MySingleList implements IList{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(23);ListNode node3 = new ListNode(34);ListNode node4 = new ListNode(45);ListNode node5 = new ListNode(56);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}
开辟了内存空间
使每个node的next域指向下一个节点的地址,连接成链表
head指向第一个节点的地址
3.实现功能接口
3.1头插添加元素
public void addFirst(int data) {ListNode node = new ListNode(data);if(this.head == null){this.head = node;}else {node.next = this.head;this.head = node;}}
对 node.next = this.head;
this.head = node;
进行解释,node的next域指向下一个节点的地址
head继续为头节点
3.2尾插法添加新元素
public void addLast(int data) {ListNode node = new ListNode(data);ListNode cur = head;if (this.head == null){this.head = node;}else {while(cur.next != null){cur = cur.next;}cur.next = node;}}
找到最后一个元素cur,cur的next指向要插入元素的地址
3.3找到下标的前驱节点
private ListNode searchPrev(int index){ListNode cur = this.head;int count = 0;while(count != index-1){cur = cur.next;count++;}return cur;}
3.4指定位置插入元素
public void addIndex(int index, int data) {//判断index的位置是否合法if(index < 0 || index >size()){return;}//插入到第一个节点位置if(index == 0){addFirst(data);}//插入到最后一个节点的位置if (index == size()){addLast(data);}//中间位置else {ListNode node = new ListNode(data);ListNode cur = searchPrev(index);node.next = cur.next;cur.next = node;}}
3.5指定元素是否存在
public boolean contains(int key) {ListNode cur = this.head;while(cur != null){if(cur.val == key){return true;}}return false;}
遍历一遍链表寻找是否有key元素
3.6找到指定元素的前驱节点
private ListNode findPrev(int key){ListNode cur = this.head;while(cur.next != null){if (cur.next.val == key){return cur;}cur = cur.next;}return null;}
3.7删除指定节点
public void remove(int key) {if (this.head == null){System.out.println("没有节点,无法删除");return;}//指定元素在头节点if (this.head.val == key){this.head = this.head.next;}else {ListNode cur = findPrev(key);//没有找到指定元素if (cur == null){System.out.println("没有找到要删除的节点");return;}//找到了指定元素ListNode del = cur.next;cur.next = del.next;}}
3.8删除所有元素为key的节点
public void removeAllKey(int key) {if(this.head == null){return;}ListNode prev = this.head;ListNode cur = this.head.next;while(cur != null){if(cur.val == key){prev.next = cur.next;cur = cur.next;}else {prev = cur;cur = cur.next;}}//删除的节点为头节点if(this.head.val == key){this.head = this.head.next;}}
3.9链表的长度
public int size() {ListNode cur = this.head;int count = 0;while(cur != null) {count++;cur = cur.next;}return count;}
3.9清空链表
public void clear() {ListNode cur = this.head;while(cur != null){ListNode curNext = cur.next;cur.next = null;cur = curNext;}head = null;}
完整代码
package mysingleList;public class MySingleList implements IList{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(23);ListNode node3 = new ListNode(34);ListNode node4 = new ListNode(45);ListNode node5 = new ListNode(56);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}@Overridepublic void addFirst(int data) {ListNode node = new ListNode(data);if(this.head == null){this.head = node;}else {node.next = this.head;this.head = node;}}@Overridepublic void addLast(int data) {ListNode node = new ListNode(data);ListNode cur = head;if (this.head == null){this.head = node;}else {while(cur.next != null){cur = cur.next;}cur.next = node;}}@Overridepublic void addIndex(int index, int data) {if(index < 0 || index >size()){return;}if(index == 0){addFirst(data);}if (index == size()){addLast(data);}else {ListNode node = new ListNode(data);ListNode cur = searchPrev(index);node.next = cur.next;cur.next = node;}}private ListNode searchPrev(int index){ListNode cur = this.head;int count = 0;while(count != index-1){cur = cur.next;count++;}return cur;}@Overridepublic boolean contains(int key) {ListNode cur = this.head;while(cur != null){if(cur.val == key){return true;}}return false;}@Overridepublic void remove(int key) {if (this.head == null){System.out.println("没有节点,无法删除");return;}if (this.head.val == key){this.head = this.head.next;}else {ListNode cur = findPrev(key);if (cur == null){System.out.println("没有找到要删除的节点");return;}ListNode del = cur.next;cur.next = del.next;}}private ListNode findPrev(int key){ListNode cur = this.head;while(cur.next != null){if (cur.next.val == key){return cur;}cur = cur.next;}return null;}@Overridepublic void removeAllKey(int key) {if(this.head == null){return;}ListNode prev = this.head;ListNode cur = this.head.next;while(cur != null){if(cur.val == key){prev.next = cur.next;cur = cur.next;}else {prev = cur;cur = cur.next;}}if(this.head.val == key){this.head = this.head.next;}}@Overridepublic int size() {ListNode cur = this.head;int count = 0;while(cur != null) {count++;cur = cur.next;}return count;}@Overridepublic void clear() {ListNode cur = this.head;while(cur != null){ListNode curNext = cur.next;cur.next = null;cur = curNext;}head = null;}@Overridepublic void display() {ListNode cur = this.head;while (cur != null){System.out.print(cur.val+" ");cur = cur.next;}System.out.println();}
}