在之前的文章笔者介绍了链表的实现:无头单向非循环链表的实现!感兴趣的各位老铁可以点进来看看:https://blog.csdn.net/weixin_64308540/article/details/128397961?spm=1001.2014.3001.5502
对于此篇博客,在一写出来,便引起了巨大反响!!那么后续来了!!今日,笔者来带领大家走进:LinkedList的模拟实现!(底层是双向链表结构)
LinkedList的底层是一个双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此,在任意位置插入或者删除元素时,不需要搬移元素,因此,效率比较高!!
我们来看一下实现的主要代码:
总体的方法:
public class MyLinkdeList {
//无头双向链表的实现
//头插法
public void addFrist(int data){
}
//尾插法
public void addLast(int data){
}
//任意位置插入,第一个数据节点的下标为0
public void addIndex(int index,int data){
}
//查找关键字key是否在链表当中
public boolean contains(int key){
}
//删除第一次出现关键字为key的节点
public void remove(int key){
}
//删除所有值为key的节点
public void removeAllkey(int key){
}
//得到链表的长度
public int size(){
}
public void display(){
}
public void clear(){
}
}
那么接下来就跟着笔者的思路,来实现这些方法吧!!
实现该方法之前的准备!每个节点所必须的东西!!
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;//永远指向链表的最后一个节点
经过上述的准备,那么我们就可以安心实现上述的方法了!!
下面笔者便以下图的链表进行讲解:
- 打印链表:
//打印链表
public void display(){
ListNode cur=head;
while (cur !=null){
System.out.print(cur.val+" ");
cur=cur.next;
}
System.out.println();
}
很简单的一个代码,想必没有什么需要讲解的吧!!
2.得到链表的长度
//得到链表的长度
public int size(){
int len=0;
ListNode cur=head;
while (cur != null){
len++;
cur=cur.next;
}
return len;
}
这个就是在遍历链表的过程中,定义了一个len,每次进行++,从而得到链表的长度!
3.查找关键字key是否在链表当中
//查找关键字key是否在链表当中
public boolean contains(int key){
ListNode cur=head;
while (cur != null) {
if (cur.val == key){//找到的情况下
return true;
}
cur=cur.next;
}
return false;
}
这个思路很简单,遍历一遍链表,当有val的值等于key的时候,直接return true即可!!如果链表遍历完毕,没有值等于key那么最后return false就行了!
4.头插法
时间复杂度为O(1)
头插法,顾名思义就是插到头节点之前呗!!
//头插法
public void addFrist(int data){
//实列化一个新的节点
ListNode node =new ListNode(data);
if (head==null){
head=node;
last=node;
}else {//先绑后面
node.next=head;
head.prev=node;
head=node;//新的头节点
}
}
上述代码,我们可以从图中得出大致思路
5.尾插法
时间复杂度为O(1)
//尾插法
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;
}
}
其实尾插法跟头插法的情况差不多!!很类似!!
6。任意位置插入,第一个数据节点的下标为0
对于想要插入数据的下标,我们首先需要判断其合法性!!然后在判断是否为头插法或者尾插法!!最后在考虑在链表内部的插入!!由于该链表是双向的链表,那么,我们可以找到index位置所对应的节点!
//任意位置插入,第一个数据节点的下标为0
public void addIndex(int index,int data){
if(index <0 || index >size()){
System.out.println("输入的位置不合法,请重新确定想要插入的位置!");
}
if (index==0){//头插法
addFrist(data);
}
if (index==size()){//尾插法
addLast(data);
}
//此时的index就是真正需要插入的地方了!
//找到index位置的下标
ListNode cur=findIndex(index);
//实列化index位置处的data节点
ListNode node=new ListNode(data);
//开始插入
node.next=cur;
cur.prev.next=node;
node.prev=cur.prev;
cur.prev=node;
}
//找到index位置的下标
public ListNode findIndex(int index){
ListNode cur=head;
while (index !=0){
index--;
cur=cur.next;
}
return cur;
}
这个列子涉及很多分析地方!!所以需要珍惜一下!好好画图分析
7.删除第一次出现关键字为key的节点
对于该案列,我们需要找到想要删除的节点!若是头节点,我们应该怎么办??若是中间或者最后的节点,我们,又应该怎么办??这些都需要我们去认真思考!
//删除第一次出现关键字为key的节点
public void remove(int key){
ListNode cur=head;
while (cur !=null){
if (cur.val==key){
//删除的是头节点
if (cur==head){
head=head.next;
//只有一个节点
if (head !=null){
head.prev=null;
}
}else {
//中间 尾巴节点
cur.prev.next=cur.next;
//不是尾巴节点
if (cur.next !=null){
cur.next.prev=cur.prev;
}else {
//是尾巴节点
last=last.prev;
}
}
}
return;
}
cur=cur.next;
}
希望大家能够理性的分析!!
8.删除所有值为key的节点
对于这个案列,我们可以经过上面的简单改变一下就可以了!!
//删除所有值为key的节点
public void removeAllkey(int key){
ListNode cur=head;
while (cur !=null){
if (cur.val==key){
//删除的是头节点
if (cur==head){
head=head.next;
//只有一个节点
if (head !=null){
head.prev=null;
}
}else {
//中间 尾巴节点
cur.prev.next=cur.next;
//不是尾巴节点
if (cur.next !=null){
cur.next.prev=cur.prev;
}else {
//是尾巴节点
last=last.prev;
}
}
}
}
cur=cur.next;
}
9.清除所有节点
第一开始笔者的想法也是,直接:head==null, last==null但是,感觉这样写虽然是这个道理,却总感觉有点儿不得劲,所以最后决定,遍历一遍链表,将每个节点的prev与last全部都置为null!!
//清除所有节点
public void clear(){
while (head !=null){
head.prev=null;
head.next=null;
head=head.next;
}
head=null;
last=null;
}
经过上面的全部代码,笔者可算是将:LinkedList的模拟实现!(底层是双向链表结构)给整理完毕了!!不容易,下面请看笔者所整理的全部代码吧!!
public class MyLinkdeList {
//无头双向链表的实现
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;//永远指向链表的最后一个节点
//头插法
public void addFrist(int data){
//实列化一个新的节点
ListNode node =new ListNode(data);
if (head==null){
head=node;
last=node;
}else {//先绑后面
node.next=head;
head.prev=node;
head=node;//新的头节点
}
}
//尾插法
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;
}
}
//任意位置插入,第一个数据节点的下标为0
public void addIndex(int index,int data){
if(index <0 || index >size()){
System.out.println("输入的位置不合法,请重新确定想要插入的位置!");
}
if (index==0){//头插法
addFrist(data);
}
if (index==size()){//尾插法
addLast(data);
}
//此时的index就是真正需要插入的地方了!
//找到index位置的下标
ListNode cur=findIndex(index);
//实列化index位置处的data节点
ListNode node=new ListNode(data);
//开始插入
node.next=cur;
cur.prev.next=node;
node.prev=cur.prev;
cur.prev=node;
}
//找到index位置的下标
public ListNode findIndex(int index){
ListNode cur=head;
while (index !=0){
index--;
cur=cur.next;
}
return cur;
}
//查找关键字key是否在链表当中
public boolean contains(int key){
ListNode cur=head;
while (cur != null) {
if (cur.val == key){//找到的情况下
return true;
}
cur=cur.next;
}
return false;
}
//删除第一次出现关键字为key的节点
public void remove(int key){
ListNode cur=head;
while (cur !=null){
if (cur.val==key){
//删除的是头节点
if (cur==head){
head=head.next;
//只有一个节点
if (head !=null){
head.prev=null;
}
}else {
//中间 尾巴节点
cur.prev.next=cur.next;
//不是尾巴节点
if (cur.next !=null){
cur.next.prev=cur.prev;
}else {
//是尾巴节点
last=last.prev;
}
}
}
return;
}
cur=cur.next;
}
//删除所有值为key的节点
public void removeAllkey(int key){
ListNode cur=head;
while (cur !=null){
if (cur.val==key){
//删除的是头节点
if (cur==head){
head=head.next;
//只有一个节点
if (head !=null){
head.prev=null;
}
}else {
//中间 尾巴节点
cur.prev.next=cur.next;
//不是尾巴节点
if (cur.next !=null){
cur.next.prev=cur.prev;
}else {
//是尾巴节点
last=last.prev;
}
}
}
}
cur=cur.next;
}
//得到链表的长度
public int size(){
int len=0;
ListNode cur=head;
while (cur != null){
len++;
cur=cur.next;
}
return len;
}
//打印链表
public void display(){
ListNode cur=head;
while (cur !=null){
System.out.print(cur.val+" ");
cur=cur.next;
}
System.out.println();
}
//清除所有节点
public void clear(){
while (head !=null){
head.prev=null;
head.next=null;
head=head.next;
}
head=null;
last=null;
}
}