前言:
大家好,我是良辰丫🍓🍓🍓,上一篇文章我和大家一起去探索了单链表的知识世界,今天我们去接触双向链表,什么?没听错,就是双向链表,比单链表更炫酷的一种链表,首先祝大家新年快乐,新年新气象,希望大家能够在新的一年心想事成。然后请跟随我的脚步,去学习了解双向链表。。🚀🚀🚀
🧑个人主页:良辰针不戳
📖所属专栏:java数据结构
🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。
💦期待大家三连,关注,点赞,收藏。
💌作者能力有限,可能也会出错,欢迎大家指正。
💞愿与君为伴,共探Java汪洋大海。
在双向链表中一个数据域会分散出两个指针域,一个pre指针指向上一个数据的地址,一个next指针指向下一个数据的地址。
下面为一个双向链表结构图,可能画的图有些抽象哈哈,是每个指针指向它所指的节点。
首先申请一个节点(基本套路),头结点为空时,说明双向链表中没有数据,那么头指针和尾指针都指向新节点。
头结点不为空时,进行头插操作,我们前面说过后绑思想,node节点先与头结点进行绑定。双向链表头插法比较特殊,两个指针,我们可以不按照后绑思想(还是建议大家就使用后绑思想,不容易出错),绑定完成后,不要忘了头指针前移。
public void addFirst(int data){ListNode node = new ListNode(data);if(head == null) {head = node;last = node;}else {node.next = head;head.prev = node;head = node;}}
- 双向链表尾插法时间复杂度为O(1),因为双向链表有尾指针,不用通过遍历寻找尾巴。
- 头结点为空时,直接让头指针和尾指针指向头结点。
- 然后通过尾指针进行连接操作。
- 最后尾指针后移。
//尾插法 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;}}
- 插入位置不合法直接退出。
- 在第一个位置插入直接调用头插法。
- 在最后一个位置插入直接调用尾插法。
- 其它情况找到要插入的位置下标,还是采用后绑法,分为四步进行插入,大家灵活掌握哦!
//任意位置插入public void addIndex(int index,int data){if(index < 0 || index > size()) {return ;}if(index == 0) {addFirst(data);return;}if(index == size()) {addLast(data);return;}ListNode cur = findIndex(index);//ListNode node = new ListNode(data);node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}private ListNode findIndex(int index) {ListNode cur = head;while (index != 0) {cur = cur.next;index--;}return cur;}
查找关键词其实和单链表一样,遍历一次找到返回true,找不到返回false。
public boolean contains(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;}
public void remove(int key){ListNode cur = head;while (cur != null) {//开始删除了if(cur.val == key) {//1. 删除的是头节点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) {//1. 删除的是头节点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();}
遍历一次链表,释放所有指针指向,注意释放前要保存next域,防止找不到下一个位置。当然了,也可以通过粗鲁的释放,直接释放首尾节点。
public void clear(){ListNode cur = head;while (cur != null) {ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}head = null;last = null;}
后序:
双向链表的内容和单链表很相似,但是这里的任意位置插入
刚开始学总会觉得有些奇怪,很正常的表现,其实没有大家想的那么难,多去思考,多去敲代码,你会有很好的收获!!!🍬🍬🍬