}
3.尾插法
思考:
思考过程与头插法一样,参考头插法
- 过程图解:
代码实现:
public void addLast(int data){
Node node = new Node(data);
//第一次插入
if(this.head == null){
this.head = node;
this.tail = node;
}
//不是第一次插入
else{
this.tail.next = node;
node.prev = this.tail;
this.tail = node;
}
}
4.任意位置插入
思考:
- 判断Index的合法性
- 首先判断是否是第一次插入—头插
- 若不是,再判断是否插入到最后位置—尾插
- 中间位置插入,需要考虑四个位置,如下图:
- 图解:
代码实现:
private void checkIndex(int index){
if(index < 0 || index > len()){
throw new RuntimeException(“index不合法!!”);
}
}
private Node searchIndex(int index){
Node cur = this.head;
while(index != 0) {
cur = cur.next;
index–;
}
return cur;
}
public void addIndex(int index,int data){
checkIndex(index);
if(index == 0){
addFirst(data);
return;
}
if(index == len()){
addLast(data);
return;
}
Node node = new Node(data);
Node cur = searchIndex(index);
node.next = cur;
node.prev = cur.prev;
cur.prev.next = node;
cur.prev = node;
}
5.查找链表中是否包含关键字 key
比较简单,直接贴代码:
public boolean containKey(int key){
Node cur = this.head;
while(cur != null){
if(cur.data == key){
return true;
}
cur = cur.next;
}
return false;
}
6.删除第一次出现关键字为 key 的节点
思考:
- 直接上图解:
代码实现:
public void deleteKey(int key){
Node cur = this.head;
while(cur != null){
if(cur.data == key){
//头节点
if(cur == this.head){
this.head = this.head.next;
this.head.prev = null;
}
//中间节点
else{
cur.prev.next = cur.next;
if(cur.next != null){
cur.next.prev = cur.prev;
}
//删除的是尾节点,只需要移动tail
else{
this.tail = cur.prev;
}
}
}
cur = cur.next;
}
}
7.删除所有出现关键字为 key 的节点
思考:
根据删除第一次出现关键字为 key 的节点,修改代码即可,考虑特殊情况
代码实现:
public void deleteAllKey(int key){
Node cur = this.head;
while(cur != null){
if(cur.data == key){
//头节点
if(cur == this.head){
this.head = this.head.next;
if(this.head != null){
this.head.prev = null;
}
}
//中间节点
else{
cur.prev.next = cur.next;
if(cur.next != null){
cur.next.prev = cur.prev;
}
//删除的是尾节点,只需要移动tail
else{
this.tail = cur.prev;
}
}
}
cur = cur.next;
}
}
8.链表长度
比较简单,直接贴代码:
public int len(){
int count = 0;
Node cur = this.head;
while(cur != null){
count++;
cur = cur.next;
}
return count;
}
9.链表清空
首先会想到以下代码:
public void clear(){
this.head = null;
}
测试打断点调试:
System.out.println(“===============”);
DoubleLinkedList doubleLinkedList3 = new DoubleLinkedList();
doubleLinkedList3.addLast(1);
doubleLinkedList3.addLast(2);
doubleLinkedList3.addLast(3);
doubleLinkedList3.addLast(4);
doubleLinkedList3.print();
doubleLinkedList3.clear();
System.out.println(“!!!”);
然后打开 cmd:
- 输入jps
![在这里插入图片描述](https://img-blog.csdnimg.cn/b468df18206741a2b307333f8afdc37c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiA5py16Iqx6Iqx,size_20,color_FFFFFF,t_70,g_se,x_16)
- 重定义到一个文本文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/6040423881a440b39401d8c6ae11dbf5.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiA5py16Iqx6Iqx,size_20,color_FFFFFF,t_70,g_se,x_16)
- 找到 log.txt 所在目录,打开 log.txt
![在这里插入图片描述](https://img-blog.csdnimg.cn/3a6d84ffdd124d439766d74bda707d56.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiA5py16Iqx6Iqx,size_20,color_FFFFFF,t_70,g_se,x_16)
- 双击打开后,ctrl + f,搜索Node
![在这里插入图片描述](https://img-blog.csdnimg.cn/f19e55eb9c4a497aa126246237eab089.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5LiA5py16Iqx6Iqx,size_19,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f3b6d1d8f651457ebbc2d70a085c8ad2.jpg)
仍然有4个,说明插入的4个数据没有被回收掉!
**故:仅仅将 head 置为null,不能实现链表清空**
解决方法:
大家可以按照上述调试检测,数据是否被回收~
public void clear(){
//一个一个节点进行释放
while(this.head != null){
Node cur = this.head.next;
this.head.prev = null;
this.head.next = null;
this.head = cur;
}
this.tail = null;
}
附全部代码:
class Node{
public int data;//数据
public Node next;//后继信息
public Node prev;//前驱信息
//提供构造方法
public Node(int data){
this.data = data;
}
}
public class DoubleLinkedList {
public Node head; //表示双向链表的头
public Node tail; //表示当前双向链表的尾
//1.打印链表
public void print(){
Node cur = this.head;
while(cur != null){
System.out.print(cur.data+" ");
cur = cur.next;
}
System.out.println();
}
//2.头插法
public void addFirst(int data){
Node node = new Node(data);
//第一次插入
if(this.head == null){
this.head = node;
this.tail = node;
}
//不是第一次插入
else{
node.next = this.head;
this.head.prev = node;
this.head = node;
}
}
//3.尾插法
public void addLast(int data){
Node node = new Node(data);
//第一次插入
if(this.head == null){
this.head = node;
this.tail = node;
}
//不是第一次插入
else{
this.tail.next = node;
node.prev = this.tail;
this.tail = node;
}
难道这样就够了吗?不,远远不够!
提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。
备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记
我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。
今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!
if(this.head == null){
this.head = node;
this.tail = node;
}
//不是第一次插入
else{
this.tail.next = node;
node.prev = this.tail;
this.tail = node;
}
难道这样就够了吗?不,远远不够!
提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。
备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记
我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。
今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!
[外链图片转存中…(img-oNEVVpQE-1719161206536)]
[外链图片转存中…(img-16JnJqbk-1719161206537)]
[外链图片转存中…(img-wKJPVd8h-1719161206537)]