赞
踩
在之前的博客中,我利用源码详细的讲解了ArrayList这个集合类(尤其是扩容机制),可以知道ArrayList的底层主要是一个动态的可变数组,容量满的时候需要进行1.5倍扩容。但是我们现在考虑这样一个问题,假设ArrayList底层数组的容量是100,我们需要存放101个元素时,当存放第101个元素时需要1.5倍扩容(扩容之后的容量是150),此时势必会造成49个存储空间的浪费!
ArrayList底层是一个数组,当我们对顺序表进行插入和删除时,需要移动大量的元素,大大提高了时间复杂度,所以可以看出ArrayList并不适用于进行大量插入和删除的操作。
针对上述ArrayList的两大缺陷,Java是否提供了其他的集合类或者数据结构来解决呢?
1.进行元素扩容时能否根据需求来进行扩容,需要多少空间就去申请多少空间;
2.在进行插入和删除的时候,可不可以不需要移动大量元素。
今天所要介绍的LinkedList集合类和链表的数据结构将很好的解决这两个问题!!!
相对于顺序表,链表是一种在逻辑上连续,在存储上不一定连续的数据结构。其中链表每个元素之间的逻辑关系是通过引用来实现的。
链表中的每一个元素称为一个节点,每一个节点至少包含两类数据:
1.数据域(存放该节点的数据信息)
2.节点域(实现链表节点与节点之间的逻辑关系,对于单链表来说只需要存储一个next即可(存储下一个节点的地址),对于双链表来说则需要存储next和prev(分别存储下一个节点和前一个节点的地址))
我们只需要重点掌握两种即可:
1.无头单向非循环链表(因为笔试的OJ题中经常会考);
2.无头双向链表(因为LinkedList的底层就是不带头的双链表)。
不同点
|
ArrayList
|
LinkedList
|
存储空间上
|
物理上一定连续
|
逻辑上连续,但物理上不一定连续
|
随机访问
|
支持:
O(1)
|
不支持:
O(N)
|
头插
|
需要搬移元素,效率低
O(N)
|
只需修改引用的指向,时间复杂度为
O(1)
|
插入
|
空间不够时需要扩容
|
没有容量的概念
|
应用场景
|
元素高效存储
+
频繁访问
|
任意位置插入和删除频繁
|
定义一个MySingleList类来实现单链表的方法,用TestMySingleList类来测试MySingleList类的方法
- import java.util.List;
-
- public class MySingleList {
- static class ListNode {
- public int val;
- public ListNode next;
-
- public ListNode(int val) {
- this.val = val;
- }
- }
-
- ListNode head;//第一节点的引用,默认为null
-
- //打印链表
- public void display() {
- ListNode cur = this.head;
- while (cur != null) {
- System.out.print(cur.val + " ");
- cur = cur.next;
- }
- System.out.println();
- }
-
- //获取链表长度
- public int size() {
- ListNode cur = this.head;
- int count = 0;
- while (cur != null) {
- count++;
- cur = cur.next;
- }
- return count;
- }
-
- //头插法
- public void addFirst(int data) {
- ListNode node = new ListNode(data);
- node.next = this.head;
- this.head = node;
- }
-
- //尾插法
- public void addLast(int data) {
- ListNode node = new ListNode(data);
- ListNode cur = this.head;
- if (this.head == null) {
- this.head = node;
- } else {
- while (cur.next != null) {
- cur = cur.next;
- }
- //此时已经处于尾节点
- cur.next = node;
- }
- }
-
- //任意index位置插入(假设第一个节点的下表为0)
- public void add(int index, int data) {
- //判断index位置的合法性
- if (index < 0 || index > size()) {
- System.out.println("index位置不合法!");//也可以抛异常
- } else if (index == 0) {
- addFirst(data);
- } else if (index == size()) {
- addLast(data);
- } else {
- //1.找到所需插入index位置的前驱
- ListNode cur = findIndexPrev(index);
- //2.修改引用的指向
- ListNode node = new ListNode(data);
- node.next = cur.next;
- cur.next = node;
- }
- }
-
- private ListNode findIndexPrev(int index) {
- ListNode cur = this.head;
- while (index - 1 != 0) {
- cur = cur.next;
- index--;
- }
- return cur;
- }
-
- //删除第一次出现的关键字key
- public void remove(int key) {
- if (this.head == null) {
- System.out.println("链表为空!");
- return;
- }
- if (this.head.val == key) {
- this.head = this.head.next;
- return;
- }
- ListNode cur = findPrev(key);//找到所需删除关键字key的前驱
- if (cur == null) {
- System.out.println("没有关键字key!");
- } else {
- cur.next = cur.next.next;
- }
- }
-
- private ListNode findPrev(int key) {
- ListNode cur = this.head;
- while (cur.next != null) {
- if (cur.val == key) {
- return cur;
- }
- cur = cur.next;
- }
- return null;
- }
-
- //删除所有出现的关键字key
- public void removeAllKey(int key) {
- if (this.head == null) {
- System.out.println("链表为空!");
- 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;
- }
- }
-
- //清空链表
- public void clear() {
- this.head = null;//单链表只需要将指向第一个节点的引用指向null即可
- }
- }

- public class TestMySingleList {
- public static void main(String[] args) {
- MySingleList mySingleList = new MySingleList();
- mySingleList.addLast(1);
- mySingleList.addLast(2);
- mySingleList.addLast(3);
- mySingleList.addLast(4);
- mySingleList.addLast(5);
- mySingleList.display();
- mySingleList.addFirst(0);
- mySingleList.display();
- mySingleList.remove(0);
- mySingleList.addLast(1);
- mySingleList.addLast(1);
- mySingleList.addLast(1);
- mySingleList.removeAllKey(1);
- mySingleList.display();
- }
- }

定义一个MyLinkedList类来实现单链表的方法,用TestMyLinkedList类来测试MyLinkedList类的方法
- public class MyLinkedList {
- static class ListNode {
- public int val;
- public ListNode prev;
- public ListNode next;
-
- public ListNode(int val) {
- this.val = val;
- }
- }
-
- ListNode head;//定义一个头引用,默认为null
- ListNode tail;//定义一个尾引用,默认为null
-
- //打印链表
- public void display() {
- ListNode cur = this.head;
- while (cur != null) {
- System.out.print(cur.val + " ");
- cur = cur.next;
- }
- System.out.println();
- }
-
- //获取链表长度
- public int size() {
- ListNode cur = this.head;
- int count = 0;
- while (cur != null) {
- count++;
- cur = cur.next;
- }
- return count;
- }
-
- //判断链表是否包含某个元素key
- public boolean contains(int key) {
- ListNode cur = this.head;
- while (cur != null) {
- if (cur.val == key) {
- return true;
- }
- cur = cur.next;
- }
- return false;
- }
-
- //头插法
- public void addFirst(int data) {
- ListNode node = new ListNode(data);
- if (this.head == null) {
- this.head = node;
- this.tail = node;
- } else {
- node.next = this.head;
- this.head.prev = node;
- this.head = node;
- }
- }
-
- //尾插法
- public void addLast(int data) {
- ListNode node = new ListNode(data);
- if (this.head == null) {
- this.head = node;
- this.tail = node;
- } else {
- this.tail.next = node;
- node.prev = this.tail;
- this.tail = node;
- }
- }
-
- //任意index位置插入(假设第一个节点的下标为0)
- public void add(int index, int data) {
- //判断index位置的合法性
- if (index < 0 || index > size()) {
- System.out.println("index位置不合法!");//也可以抛异常
- } else if (index == 0) {
- addFirst(data);
- } else if (index == size()) {
- addLast(data);
- } else {
- //1.找到index位置的节点
- ListNode cur = findIndexPrev(index);
- //2.修改指向的引用
- ListNode node = new ListNode(data);
- node.next = cur;
- node.prev = cur.prev;
- cur.prev.next = node;
- cur.prev = node;
- }
- }
-
- private ListNode findIndexPrev(int index) {
- ListNode cur = this.head;
- while (index != 0) {
- cur = cur.next;
- index--;
- }
- return cur;
- }
-
- //删除第一次出现的关键字key
- public void remove(int key) {
- if (this.head == null) {
- System.out.println("链表为空!");
- return;
- }
- ListNode cur = this.head;
- while (cur != null) {
- if (cur.val == key) {
- if (cur == this.head) {
- this.head = this.head.next;
- if (this.head != null) {
- this.head.prev = null;
- } else {
- this.tail = null;
- }
- } else {
- cur.prev.next = cur.next;
- if (cur.next != null) {
- cur.next.prev = cur.prev;
- } else {
- this.tail = cur.prev;
- this.tail.next = null;
- }
- }
- return;
- }
- cur = cur.next;
- }
- }
-
- //删除所有出现的关键字key
- public void removeAllKey(int key) {
- if (this.head == null) {
- System.out.println("链表为空!");
- return;
- }
- ListNode cur = this.head;
- while (cur != null) {
- if (cur.val == key) {
- if (cur == this.head) {
- this.head = this.head.next;
- if (this.head != null) {
- this.head.prev = null;
- } else {
- this.tail = null;
- }
- } else {
- cur.prev.next = cur.next;
- if (cur.next != null) {
- cur.next.prev = cur.prev;
- } else {
- this.tail = cur.prev;
- this.tail.next = null;
- }
- }
- }
- cur = cur.next;
- }
- }
-
- //清空链表
- public void clear() {
- ListNode cur = this.head;
- while (cur != null) {
- ListNode curNext = cur.next;
- cur.prev = null;
- cur.next = null;
- cur = curNext;
- }
- this.head = null;
- this.tail = null;
- }
- }

- public class TestMyLinkedList {
- public static void main(String[] args) {
- MyLinkedList myLinkedList = new MyLinkedList();
- myLinkedList.addLast(1);
- myLinkedList.addLast(2);
- myLinkedList.addLast(3);
- myLinkedList.addLast(4);
- myLinkedList.addLast(5);
- myLinkedList.addFirst(0);
- myLinkedList.display();
- myLinkedList.remove(0);
- myLinkedList.display();
- myLinkedList.add(2,10);
- myLinkedList.display();
- myLinkedList.addLast(1);
- myLinkedList.addLast(1);
- myLinkedList.removeAllKey(1);
- myLinkedList.display();
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。