文章目录
LinkedList
在ArrayList中我们在顺序表中对其进行了模拟。通过代码,我们也就明白了。通过数组下标,寻找某个元素是非常的快捷键,但是向其中插入数数据,我们就要将插入的位置后的数据进行,向后挪移。这样的速度是非常慢的。
为了应对这种情况,就需要一种新的数据结构,也就是LinkedList。这种数据结构就类似于火车。对这种数据结构进行插入数据的操作,就类似于火车的车厢,向中间插入时,先跟前面一节车厢进行链接,然后链接后面一节车厢,通过锚定的方式进行连接。
画个图进行表示:
我们将它与数据结构结合。
我们看看java本身对于这个代码的处理。
static class ListNode{
public int val;//数据
public ListNode next;//地址,也就是引用,类型我们定义成与类相同,这样我们就可以通过引用调取下一个车厢的数据和引用
public ListNode(int val){
this.val=val;
}
public ListNode(){
}
}
好了到了这一步已经将链表的大体结构解释的差不多了。诺还有不懂的,可以私信我。可以免费给大家详细讲述。
LinkedList
如何自我实现
框架流程:
public class SingleLinkedList {
//头插法
public void addFirst(int data){
}
//尾插法
public void addLast(int data){
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
return false;
}
//删除第一次出现关键字为key的节点
public void remove(int key){
}
//删除所有值为key的节点
public void removeAllKey(int key){
}
//得到单链表的长度
public int size(){
return -1;
}
}
这里我贴上我的实现
public ListNode head;
public int cont;
static class ListNode{
public int val;
public ListNode next;
public ListNode(int val){
this.val=val;
}
public ListNode(){
}
}
//头插法
public void addFirst(int data){
ListNode node=new ListNode(data);
node.next=head;
head=node;
cont++;
}
//尾插法
public void addLast(int data){
ListNode listNode=new ListNode(data);
if (head==null){
head=listNode;
return;
}
ListNode cur=head;
while (cur.next!=null){
cur=cur.next;
}
cur.next=listNode;
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
if (index<0&&index>cont){
throw new ListIndexOutOfException("位置错误");
}
if (index==0){
addFirst(data);
return ;
}
if (index==cont){
addLast(data);
return;
}
int count=0;
ListNode cur=head;
while (count!=index-1){
cur=cur.next;
count++;
}
ListNode listNode=new ListNode(data);
listNode.next=cur.next;
cur.next=listNode;
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
if (head==null){
return false;
}
ListNode cur=head;
while (cur.next!=null){
if (cur.val==key){
return true;
}
cur=cur.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){
break;
}
cur=cur.next;
}
if (cur.next==null){
return;
}
cur.next=cur.next.next;
}
//删除所有值为key的节点
public void removeAllKey(int key){
if (head==null){
return;
}
if (head.val==key){
head=head.next;
return;
}
ListNode cur=head.next;
ListNode provt=head;
while (cur!=null){
if (cur.val==key){
provt.next=cur.next;
}
provt=cur;
cur=cur.next;
}
}
//得到单链表的长度
public int size(){
return cont;
}
public void display(){
ListNode cur=head;
while (cur!=null){
System.out.println(cur.val+" ");
cur=cur.next;
}
}
public void clear(){
head=null;
}
到此我们就自我实现了一个单链表,然而我相信你们也就看的出来,单链表是一个只能前进不能后退的链表,那么如何实现倒退呢?其实可以在节点中除next之外加一个类似next作用的链接器。如此就可以,我们将它命名为frist,让它去记录上一个节点的地址。
插入效率的解决
通过上述的任意插入,我们可以看到,我们并没有挪移后面的元素,而是暴力直接插入所在位置的地方。相当于成语:横插一脚,再次我们最多在链表末尾插入,也就遍历一遍,而数组诺是在头插入就是在遍历一遍的同时,还得挪移一遍。这样插入的效率大大提高了
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
if (index<0&&index>cont){
throw new ListIndexOutOfException("位置错误");
}
if (index==0){
addFirst(data);
return ;
}
if (index==cont){
addLast(data);
return;
}
int count=0;
ListNode cur=head;
while (count!=index-1){
cur=cur.next;
count++;
}
ListNode listNode=new ListNode(data);
listNode.next=cur.next;
cur.next=listNode;
}
技术细节
源代码:
返回值 | 方法 | 解释 |
---|---|---|
boolean | add(E e) | 尾插 e |
void | add(int index, E element) | 将 e 插入到 index 位置 |
boolean | addAll(Collection<? extends E> c) | 尾插 c 中的元素 |
E | remove(int index) | 删除 index 位置元素 |
boolean | remove(Object o) | 删除遇到的第一个 o |
E | get(int index) | 获取下标 index 位置元素 |
E | set(int index, E element) | 将下标 index 位置元素设置为 element |
void | clear() | 清空 |
boolean | contains(Object o) | 判断 o 是否在线性表中 |
int | indexOf(Object o) | 返回第一个 o 所在下标 |
int | lastIndexOf(Object o) | 返回最后一个 o 的下标 |
List | subList(int fromIndex, int toIndex) | 截取部分 list |
小结
- LinkedList实现了List接口
- LinkedList的底层使用了双向链表
- LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
- LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
- LinkedList比较适合任意位置插入的场景
ArrayList和 LinkedList的区别
不同点 | ArrayList | LinkedList |
---|---|---|
存储空间上 | 物理上一定连续 | 逻辑上连续,但物理上不一定连续 |
随机访问 | 支持O(1) | 不支持:O(N) |
头插 | 需要搬移元素,效率低O(N) | 只需修改引用的指向,时间复杂度为O(1) |
插入 | 空间不够时需要扩容 | 没有容量的概念 |
应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
其他文章接口
1.String方法(重要,对于操作字符串有巨大的帮助)
2.java常用的接口及其方法(包含拷贝,比较,排序,构造器)
3.初阶数据结构
3.1 顺序表:ArrayList
3.2 链表:LinkedList
3.3 栈:Stack
3.4 队列:Queue
3.5 二叉树:Tree
3.6 优先级队列:PriorityQueue(堆排序)
3.7 Map和Set
HashMap和HashSet,TreeMap和TreeSet
文章链接
4. 排序(7种方式)
4.1 插入排序(两种)
4.2 选择排序(两种)
4.3 快速排序
4.4 堆排序
里面有堆排序的实现和逻辑
文章链接