Java实现双向链表的基本操作
Posted 一朵花花
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现双向链表的基本操作相关的知识,希望对你有一定的参考价值。
Java实现无头双向链表
介绍:
双向链表比单链表多了一个 prev(前驱) 域,指向前一个节点data:数据
next:后继信息
prev:前驱信息
.
无头双向链表图解:
双向链表节点的定义
class Node{
public int data;//数据
public Node next;//后继信息
public Node prev;//前驱信息
//提供构造方法
public Node(int data){
this.data = data;
}
}
1.链表的打印
直接上代码:
public void print(){
Node cur = this.head;
while(cur != null){
System.out.print(cur.data+" ");
cur = cur.next;
}
System.out.println();
}
2.头插法
思考:
- 首先判断是不是第一次插入
- 若是第一次插入,让 head 和 tail 都指向 待插入节点node
- 若不是第一次插入,修改对应的值实现头插即可
- 图解:
代码实现:
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;
}
}
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
- 重定义到一个文本文件
- 找到 log.txt 所在目录,打开 log.txt
- 双击打开后,ctrl + f,搜索Node
仍然有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;
}
}
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;
}
//4.任意位置插入,第一个数据节点为0号下标
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 的节点
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(){
//一个一个节点进行释放
while(this.head != null){
Node cur = this.head.next;
this.head.prev = null;
this.head.next = null;
this.head = cur;
}
this.tail = null;
}
}
快下来试着敲敲叭~
以上是关于Java实现双向链表的基本操作的主要内容,如果未能解决你的问题,请参考以下文章