文章目录
- 直奔主题:单向链表 和 双向链表 的 数据结构(下面是不带头的)
-
- 节点删除,双向链表不需要借助前驱节点
-
- 先来看单向链表是怎么来删除节点的
- 废话不多说,实战中学习
-
- 模拟实现双向链表(不带头)
-
- 对双向列表的节点,进行抽象 ,写出一个类
- 而对于 双向链表抽象出的类,它必须具有两个属性 head(头节点) 和 last(尾结点)
- 因为 我们已经有了单链表的基础,所以一些简单功能我就直接放上来
-
- display 打印val值 功能
- contains 功能 - 确认是包含指定val数据
- size - 得到双向链表的长度
- remove 删除 指定key值的节点(这里应该是布尔类型,但是我为了方便 就 void 的了,影响不大)
- removeAll -删除所有值为key的节点 就是 把 remove 中 那个 if 包裹的 return 删掉 就可以了
- clear - 清空 链表节点
- 直至双向链表的所有功能就都实现了,随后附上整体程序(附赠带头的双向链表)
博主突然记起来了!好像还漏一个双向链表没有写博客,今天就给大家补上。
建议先看 这篇文章 顺序表 和 链表 - 单向链表部分 ,再来看这篇双向,本篇文章可能相对粗略,所以建议你们先看单向链表的文章,有助于你们理解,
直奔主题:单向链表 和 双向链表 的 数据结构(下面是不带头的)
双向链表 和 单向链表的区别,就在于 双向 比 单向 多个 一个前驱地址。而且 你会发现 正因为有了前驱地址,所以所以这个链表,它有两种走向,这也是这个链表为什么叫做双向链表的原因之一。
双向链表的好处
节点删除,双向链表不需要借助前驱节点
先来看单向链表是怎么来删除节点的
总结:
单向链表在删除一个节点的时候,需要借助前驱节点,才能删除。
再来看双向的
废话不多说,实战中学习
模拟实现双向链表(不带头)
对双向列表的节点,进行抽象 ,写出一个类
而对于 双向链表抽象出的类,它必须具有两个属性 head(头节点) 和 last(尾结点)
因为 我们已经有了单链表的基础,所以一些简单功能我就直接放上来
display 打印val值 功能
public void display() { //和单链表的打印方式是一样 ListNode cur = this.head; while (cur != null) { System.out.print(cur.val +" "); cur = cur.next; } System.out.println(); }
contains 功能 - 确认是包含指定val数据
public boolean contains(int key) { ListNode cur = this.head; while (cur != null) { if (cur.val == key) { return true; } cur = cur.next; } return false; }
size - 得到双向链表的长度
public int size() { int count = 0; ListNode cur = this.head; while (cur != null) { count++; cur = cur.next; } return count; }
public void addFirst(int data) { ListNode node = new ListNode(data); if (this.head == null) { this.head = node; this.last = node; } else { node.next = this.head; this.head.prev = node; this.head = node; } }
###尾插法
public void addLast(int data) { ListNode node = new ListNode(data); if (this.head == null) { this.head = node; this.last = node; return; } last.next = node; node.prev = last; last = node; }
remove 删除 指定key值的节点(这里应该是布尔类型,但是我为了方便 就 void 的了,影响不大)
public void remove(int key) { if(this.head==null){ // 链表为空,无节点的情况 return;// 默认false } ListNode cur = this.head; while(cur!=null){ if(cur.val==key){ // 删除成功就 return 结束程序 if(this.head == cur){ // 如果第一个节点就是要删除的节点 this.head = this.head.next;// head == null if(this.head !=null){ // 防止空指针异常,也是为了 判断头节点后面是否还有节点 this.head.prev = null; }else{ // 如果只有一个节点,且已经被删除了,也就是说链表中没有节点了,last 置为null this.last = null; } } else{ // 头节点不是要删除的节点 cur.prev.next = cur.next;// 如果是 最后一个节点 此时 cur.next == null if(cur.next!=null){ // 确保不是最后一个节点,以防空指针异常 // 也就是 中间情况 cur.next.prev = cur.prev; }else{ // 最后一个节点 是 删除的对象 this.last = this.last.prev;// 因为已经将新的尾巴节点的next置为null了,所以只需要改变 last的指向 } } return;// 删除成功,ture ,在 if(cur.val==key) 的范围 } cur= cur.next;// cur 代替 head 遍历链表 } }
removeAll -删除所有值为key的节点 就是 把 remove 中 那个 if 包裹的 return 删掉 就可以了
public void remove(int key) { if(this.head==null){ // 链表为空,无节点的情况 return;// 默认false } ListNode cur = this.head; while(cur!=null){ if(cur.val==key){ // 删除成功就 return 结束程序 if(this.head == cur){ // 如果第一个节点就是要删除的节点 this.head = this.head.next;// head == null if(this.head !=null){ // 防止空指针异常,也是为了 判断头节点后面是否还有节点 this.head.prev = null; }else{ // 如果只有一个节点,且已经被删除了,也就是说链表中没有节点了,last 置为null this.last = null; } } else{ // 头节点不是要删除的节点 cur.prev.next = cur.next;// 如果是 最后一个节点 此时 cur.next == null if(cur.next!=null){ // 确保不是最后一个节点,以防空指针异常 // 也就是 中间情况 cur.next.prev = cur.prev; }else{ // 最后一个节点 是 删除的对象 this.last = this.last.prev;// 因为已经将新的尾巴节点的next置为null了,所以只需要改变 last的指向 } } // return; 删除这句 就ok了 } cur= cur.next;// cur 代替 head 遍历链表 } }
clear - 清空 链表节点
public void clear() { while(this.head!=null){ // 将链表中,每个元素置为null ListNode headNext = this.head.next; this.head.prev =null; this.head.next = null; this.head = headNext;// head 在此过程中,置为null,因为 最后一个元素的next 等null, } this.last = null;// last 最后 也置为null } }
直至双向链表的所有功能就都实现了,随后附上整体程序(附赠带头的双向链表)
至于如何测试功能,直接新建一个类,在main方法中,new一个 DoubleLinkedList 对象,通过对象的引用,去调用 双向链表的功能。参数自己决定。
class ListNode { public int val; public ListNode prev; public ListNode next; public ListNode(int val) { this.val = val; } } public class DoubleLinkedList { public ListNode head = new ListNode(-1);//指向双向链表的头节点 public ListNode last;//指向的是尾巴节点 // 带头 public void display() { //和单链表的打印方式是一样 if(this.head.next==null){ return; } ListNode head1 = this.head.next; ListNode cur = head1; while (cur != null) { System.out.print(cur.val +" "); cur = cur.next; } System.out.println(); } // 不带头 // public void display() { 和单链表的打印方式是一样 // ListNode cur = this.head; // while (cur != null) { // System.out.print(cur.val +" "); // cur = cur.next; // } // System.out.println(); // } //得到单链表的长度 // 带头的 public int size() { if(this.head.next==null){ return 0; } int count = 0; ListNode cur = this.head.next; while (cur != null) { count++; cur = cur.next; } return count; } // 不带头 // public int size() { // int count = 0; // ListNode cur = this.head; // while (cur != null) { // count++; // cur = cur.next; // } // return count; // } //查找是否包含关键字key是否在单链表当中 // 带头的 public boolean contains(int key) { if(this.head.next==null){ return false; } ListNode cur = this.head.next; while (cur != null) { if (cur.val == key) { return true; } cur = cur.next; } return false; } // 不带头的 // public boolean contains(int key) { // ListNode cur = this.head; // while (cur != null) { // if (cur.val == key) { // return true; // } // cur = cur.next; // } // return false; // } //头插法 // 带头的 public void addFirst(int data) { ListNode node = new ListNode(data); if(this.head.next == null){ this.head.next = node; node.prev = head; this.last = node; }else{ node.next = this.head.next; node.prev = this.head; this.head.next = node; } } // 不带带头的 // public void addFirst(int data) { // ListNode node = new ListNode(data); // if (this.head == null) { // this.head = node; // this.last = node; // } else { // node.next = this.head; // this.head.prev = node; // this.head = node; // } // } //尾插法 // 带头的 public void addLast(int data) { ListNode node = new ListNode(data); if(this.head.next == null){ this.head.next = node; node.prev = head; this.last = node; return; } this.last.next = node; node.prev = this.last; this.last = node; } // 不带头的: // public void addLast(int data) { // ListNode node = new ListNode(data); // if (this.head == null) { // this.head = node; // this.last = node; // return; // } // last.next = node; // node.prev = last; // last = node; // } //任意位置插入,第一个数据节点为0号下标 // 带头的 public void addIndex(int index, int data) { if(index<0||index>size()){ System.out.println("index 位置不合法"); return ; } ListNode node = new ListNode(data); if(index == 0){ addFirst(data); return ; } if (index == size()){ addLast(data); return ; } ListNode cur = searchIndex(index); node.next = cur; node.prev = cur.prev; cur.prev.next =node; cur.prev = node; } public ListNode searchIndex(int index){ ListNode cur = this.head.next; while(index!=0){ cur = cur.next; index--; } return cur; } // 不带头的 // public void addIndex(int index, int data) { // if(index<0||index>size()){ // System.out.println("index 位置不合法"); // return ; // } // ListNode node = new ListNode(data); // if(index == 0){ // addFirst(data); // return ; // } // if (index == size()){ // addLast(data); // return ; // } // ListNode cur = searchIndex(index); // node.next = cur; // node.prev = cur.prev; // cur.prev.next =node; // cur.prev = node; // } // public ListNode searchIndex(int index){ // ListNode cur = this.head; // while(index!=0){ // cur = cur.next; // index--; // } // return cur; // } //删除第一次出现关键字为key的节点 // 带头的 public void remove(int key) { if (this.head.next == null) { return; } ListNode head1 = this.head.next; ListNode cur = head1; while (cur != null) { if (cur.val == key) { if (head1 == cur) { if (cur.next == null) { this.head.next = null; this.last = this.head; }else { cur.prev.next = cur.next; cur.next.prev = cur.prev; } } else { cur.prev.next = cur.next; if (cur.next != null) { cur.next.prev = cur.prev; } else { this.last = this.last.prev; } } return; } cur = cur.next; } } // 不带头的 // public void remove(int key) { // if(this.head==null){ // return; // } // ListNode cur = this.head; // while(cur!=null){ // if(cur.val==key){ // if(this.head == cur){ // this.head = this.head.next; // if(this.head !=null){ // this.head.prev = null; // }else{ // this.last = null; // } // } else{ // cur.prev.next = cur.next; // if(cur.next!=null){ // cur.next.prev = cur.prev; // }else{ // this.last = this.last.prev; // } // } // return; // } // cur= cur.next; // } // } //删除所有值为key的节点 // 带头的 public void removeAllKey(int key) { if (this.head.next == null) { return; } ListNode head1 = this.head.next; ListNode cur = head1; while (cur != null) { if (cur.val == key) { if (head1 == cur) { if (cur.next == null) { this.head.next = null; this.last = this.head; }else { cur.prev.next = cur.next; cur.next.prev = cur.prev; } } else { cur.prev.next = cur.next; if (cur.next != null) { cur.next.prev = cur.prev; } else { this.last = this.last.prev; } } } cur = cur.next; } } // 不带头的 // public void removeAllKey(int key) { // if(this.head==null){ // return; // } // ListNode cur = this.head; // while(cur!=null){ // if(cur.val==key){ // if(this.head == cur){ // this.head = this.head.next; // if(this.head !=null){ // this.head.prev = null; // }else{ // this.last = null; // } // } else{ // cur.prev.next = cur.next; // if(cur.next!=null){ // cur.next.prev = cur.prev; // }else{ // this.last = this.last.prev; // } // } return; // } // cur= cur.next; // } // } // 不带头 // public void clear() { // while(this.head!=null){ // ListNode headNext = this.head.next; // this.head.prev =null; // this.head.next = null; // this.head = headNext; // } // this.last = null; // } // //} // 带头 public void clear() { if(this.head.next == null){ this.last = null; this.head = null; return; }else { while(this.head.next!=null){ ListNode headNext = this.head.next; this.head.prev =null; this.head.next = null; this.head = headNext; } this.last = null; } } }