一、什么是LinkedList
- LinkedList底层就是一个双向链表,来实现一个双向链表。
public class MyLinkedList {
static class ListNode{
public int val;
public ListNode prev;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public ListNode head;
public ListNode last;
//1 打印双向链表
public void display(){
ListNode cur=head;
while(cur!=null){
System.out.print(cur.val+" ");//注意这里是" " ,不是' ',否则出错
cur=cur.next;
}
System.out.println();
}
//2 头插法
public void addFirst(int data){
ListNode node=new ListNode(data);
if(head==null){//空链表
head=node;
last=node;
return;
}
node.next=head;
head.prev=node;
head=node;
}
//3 尾插法
public void addLast(int data){
ListNode node=new ListNode(data);
if(head==null){
head=node;
last=node;
}else{
last.next=node;
node.prev=last;
last=node;
}
}
//4 在任意位置插入一个结点
public ListNode findIndex(int index){
ListNode cur=head;
while(index!=0){
cur=cur.next;
index--;
}
return cur;
}
public void addIndex(int index,int data){//先判断index位置的合法性
if(index<0 || index>size()){
throw new indexNotLegalException("index位置不合法!");
}
if(index==0){//头插
addFirst(data);
}else if(index==size()){//尾插
addLast(data);
}else{//中间插
ListNode node=new ListNode(data);
ListNode cur=findIndex(index);
node.next=cur;
cur.prev.next=node;
node.prev=cur.prev;
cur.prev=node;
}
}
//5 查找是否包含关键字key
public boolean contain(int key){
ListNode cur=head;
while(cur!=null){//遍历查找
if(cur.val==key){
return true;
}
cur=cur.next;
}
return false;
}
//6 删除第一次出现关键字key 的结点
public void remove(int key){
ListNode cur=head;
while(cur!=null){
if(cur.val==key){
if(cur==head){//删除的是头节点
head=head.next;
head.prev=null;
return;
}else if(cur==last){//删除的是尾巴结点
last=cur.prev;
last.next=null;
return;
}else{//删除的是中间节点
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
return;
}
}
cur=cur.next;
}
}
//7 删除所有值为key的结点数据
public void removeAll(int key){
ListNode cur=head;
while(cur!=null){
if(cur.val==key){
if(cur==head){//删除的是头节点
head=head.next;
head.prev=null;
}else if(cur==last){//删除的是尾巴结点
last=cur.prev;
last.next=null;
}else{//删除的是中间节点
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
}
}
cur=cur.next;
}
}
//8 单链表的长度
public int size(){
ListNode cur=head;
int count=0;
while(cur!=null){
count++;
cur=cur.next;
}
return count;
}
//9 清空无头双向链表
public void clear(){
ListNode cur=head;
while(cur!=null){
ListNode curNext=cur.next;
cur.next=null;
cur.prev=null;
cur=curNext;
}
//一个一个删除所有结点的引用
head=null;//头节点没有了前后引用,但是自身的值还存在,又被head引用,所以置空
last=null;//没有引用就清空,最后要把head和last这两个引用也置空
}
}
二、 LinkedList的使用
- LinkedList的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。
- LinkedList实现了List接口;
- LinkedList的底层使用了双向链表;
- LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问;
- LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1);(注意区分3.4两点)
public class Test {
public static void main(String[] args) {
MyLinkedList myLinkedList=new MyLinkedList();
myLinkedList.addFirst(45);
myLinkedList.addFirst(34);
myLinkedList.addFirst(23);
myLinkedList.addFirst(45);
myLinkedList.addLast(99);
int s=myLinkedList.size();
System.out.println(s);
myLinkedList.addIndex(2,999);
myLinkedList.display();
boolean ret=myLinkedList.contain(0);
System.out.println(ret);
myLinkedList.removeAll(45);
myLinkedList.display();
myLinkedList.clear();
myLinkedList.display();
}
}
三、 LinkedList的遍历
public class Test {
public static void main(String[] args) {
ArrayList<Integer> arrayList=new ArrayList<>();
LinkedList<Integer> linkedList=new LinkedList<>();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
System.out.println("========for循环遍历=========");
for(int i=0;i<linkedList.size();i++){
System.out.println(linkedList.get(i)+" ");
}
System.out.println();
System.out.println("=====for each遍历======");
for(Integer x:linkedList){
System.out.println(x+" ");
}
System.out.println();
System.out.println("==========迭代器遍历===========");
ListIterator<Integer> it=linkedList.listIterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
}
}
四、ArrayList与LinkedList的区别
- 随机访问:存取第N个数据,不需要访问前N-1个数据,可以直接对第N个数据进行操作(数组);
- 非随机访问:存取第N个数据时,必须先访问前N-1个数据(链表);