Java数据结构与算法------双向链表
2020-07-07 19:04
148 查看
单链表的每个结点包含一个数据域和一个指向下一结点的指针域
相对于单链表,双向链表多了一个指向前一个结点的指针
创建结点
class HeroNode2{ public int no;//英雄的编号 public String name;//英雄的名字 public String nickname;//英雄的昵称 public HeroNode2 next;//指向下一个结点 public HeroNode2 pre;//指向前一个结点 //构造器 public HeroNode2(int hno,String hname,String hnickname) { this.no=hno; this.name=hname; this.nickname=hnickname; } //为了显示方法,重写toString @Override public String toString() { return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]"; } }
插入结点(插入到链表尾部)
- 依然是先找到最后一个结点
- 使这个结点的next指向新的结点
- 使新结点的pre指向这个结点
public void add(HeroNode2 heronode) { //因为head结点不能动,所以需要一个辅助遍历的temp HeroNode2 temp = head; //遍历链表,找到最后的结点 while(true) { if(temp.next == null) { break; } //如果没有没有找到最后结点 temp = temp.next; } //当退出循环时,temp就指向了链表的最后 //将最后这个结点的next 指向新的结点 temp.next=heronode; heronode.pre=temp; }
插入结点(考虑顺序的插入)
- 此时插入 ,当我们找到相应的位置后(temp)
- 先把新的结点的next指向temp.next
- 接着把temp.next.pre指向新的结点(这里因为可能该位置是最后一个结点,所以temp.next.pre无法执行,需要一个判断)
- 再把新结点的pre指向temp
- 最后把temp的next指向新的结点
public void addByOrder(HeroNode2 heronode) { //还是头结点不能动,所以定义一个辅助的temp,帮助找到要添加的位置 //因为是单链表,因此temp要找到 位于添加位置的前一个结点,否则添加不了 HeroNode2 temp= head; boolean flag = false;//标识添加的编号是否存在,默认为false while(true) { if(temp.next==null) {//说明此事temp已经在链表的最后 break; } if(temp.next.no>heronode.no) {//位置就在temp的后面插入(因为如果此时条件成立,那么说明要加入的结点排名就在temp与temp.next之间) break; }else if(temp.next.no==heronode.no) {//如果此时条件成立,说明此时新加入的结点的编号已经存在 flag = true;//说明编号存在 break; } temp=temp.next; } //判断flag的值 if(flag) {//此时说明要加入的结点的编号已经存在,因此不能加入 System.out.printf("准备插入的英雄编号%d已经存在,不能加入\n",heronode.no); } else { //插入到链表中,temp的后面 heronode.next=temp.next; if(temp.next!=null) { temp.next.pre=heronode; } heronode.pre=temp; temp.next=heronode; } }
修改结点
此处与单链表一致`
public void update(HeroNode2 newheronode) {//根据这个新结点的no来修改 //判断是否为空 if(head.next==null) { System.out.println("链表为空"); return; } //找到需要修改的结点 还是先定义一个辅助结点 HeroNode2 temp = head; boolean flag = false;//表示是否找到该结点 while(true) { if(temp == null) { break;//表示链表已经遍历结束 } if (temp.no==newheronode.no) { //找到了需要修改的结点 flag=true; break; } temp=temp.next; } //根据flag判断是否找到需要修改的结点 if(flag) { temp.name=newheronode.name; temp.nickname=newheronode.nickname; }else { System.out.printf("没有找到编号%d的结点",newheronode.no); } }
删除结点
- 在单链表中我们删除一个结点需要找到这个结点的上一个结点,而这个双链表删除结点只用找到这个结点就行
- 当我们找到这个结点temp后执行:temp.pre.next=temp.next 即把该结点的上一个结点的next指向该结点的下一个结点
- 接着执行:temp.next.pre=temp.pre(这里同样原因,需要一个判断),即把该结点的下一个结点的pre指向该结点的上一个结点
public void delete(int no) { //判断是否为空 if(head.next==null) { System.out.println("链表为空"); return; } HeroNode2 temp = head.next; boolean flag = false;//判断是否找到需要删除结点的前一个结点 while(true) { if(temp == null) { break;//表示链表已经遍历结束 } if(temp.no==no) {//找到了需要删除的结点 flag = true; break; } temp=temp.next; } if(flag) {//temp为被删除结点的上一个结点,temp.next为被删除结点,temp.next.next为被删除结点的下一个结点 temp.pre.next=temp.next; //这里有个问题:如果要删除的结点是最后一个结点,那么temp.next.pre则无法执行,所以要进行一个判断 if(temp.next!=null) { temp.next.pre=temp.pre; } }else { System.out.println("没有找到要删除的结点"); } }
总代吗:
package Linkedlist; public class doubleLinkList { public static void main(String[] args) { System.out.println("双向链表的测试"); //先创建几个结点 HeroNode2 heroNode = new HeroNode2(1,"宋江","及时雨"); HeroNode2 heroNode2 = new HeroNode2(2,"卢俊义","玉麒麟"); HeroNode2 heroNode3 = new HeroNode2(3,"吴用","智多星"); HeroNode2 heroNode4 = new HeroNode2(4,"林冲","豹子头"); //创建双向链表对象 DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); // doubleLinkedList.add(heroNode); // doubleLinkedList.add(heroNode2); // doubleLinkedList.add(heroNode3); // doubleLinkedList.add(heroNode4); doubleLinkedList.addByOrder(heroNode4); doubleLinkedList.addByOrder(heroNode2); doubleLinkedList.addByOrder(heroNode3); doubleLinkedList.addByOrder(heroNode); doubleLinkedList.list(); System.out.println("修改后的链表情况"); //修改一个结点 HeroNode2 newheronode = new HeroNode2(3,"吴用","无量天尊"); doubleLinkedList.update(newheronode); doubleLinkedList.list(); System.out.println("删除后的链表情况"); doubleLinkedList.delete(2); doubleLinkedList.list(); } } class DoubleLinkedList{ //先初始化一个头结点,因为在遍历时,头结点在最前面,所以头结点不变,以防单链表找不到头结点 private static HeroNode2 head = new HeroNode2(0,"",""); public static HeroNode2 getHead() { return head; } //显示链表 public void list() { //先判断链表是否为空 if(head.next==null) { System.out.println("链表为空"); return; } //因为头结点不能动,因此需要辅助变量遍历 HeroNode2 temp = head.next; while(true) { //判断是否到链表最后 if(temp==null) { break; } //如果不为空,输出结点的信息 System.out.println(temp); //将temp后移 temp=temp.next; } } //添加一个结点内容 public void add(HeroNode2 heronode) { //因为head结点不能动,所以需要一个辅助遍历的temp HeroNode2 temp = head; //遍历链表,找到最后的结点 while(true) { if(temp.next == null) { break; } //如果没有没有找到最后结点 temp = temp.next; } //当退出循环时,temp就指向了链表的最后 //将最后这个结点的next 指向新的结点 temp.next=heronode; heronode.pre=temp; } //第二种添加方式,根据英雄的排名插入到指定位置(如果有这个排名则添加失败,即这名英雄已经在链表) public void addByOrder(HeroNode2 heronode) { //还是头结点不能动,所以定义一个辅助的temp,帮助找到要添加的位置 //因为是单链表,因此temp要找到 位于添加位置的前一个结点,否则添加不了 HeroNode2 temp= head; boolean flag = false;//标识添加的编号是否存在,默认为false while(true) { if(temp.next==null) {//说明此事temp已经在链表的最后 break; } if(temp.next.no>heronode.no) {//位置就在temp的后面插入(因为如果此时条件成立,那么说明要加入的结点排名就在temp与temp.next之间) break; }else if(temp.next.no==heronode.no) {//如果此时条件成立,说明此时新加入的结点的编号已经存在 flag = true;//说明编号存在 break; } temp=temp.next; } //判断flag的值 if(flag) {//此时说明要加入的结点的编号已经存在,因此不能加入 System.out.printf("准备插入的英雄编号%d已经存在,不能加入\n",heronode.no); } else { //插入到链表中,temp的后面 heronode.next=temp.next; if(temp.next!=null) { temp.next.pre=heronode; } heronode.pre=temp; temp.next=heronode; } } //根据编号修改结点信息, public void update(HeroNode2 newheronode) {//根据这个新结点的no来修改 //判断是否为空 if(head.next==null) { System.out.println("链表为空"); return; } //找到需要修改的结点 还是先定义一个辅助结点 HeroNode2 temp = head; boolean flag = false;//表示是否找到该结点 while(true) { if(temp == null) { break;//表示链表已经遍历结束 } if (temp.no==newheronode.no) { //找到了需要修改的结点 flag=true; break; } temp=temp.next; } //根据flag判断是否找到需要修改的结点 if(flag) { temp.name=newheronode.name; temp.nickname=newheronode.nickname; }else { System.out.printf("没有找到编号%d的结点",newheronode.no); } } //从双向链表中删除一个结点 //在单链表中需要找到要删除结点的前一个结点,而双向链表中可以直接找到要删除结点,找到后可自我删除 public void delete(int no) { //判断是否为空 if(head.next==null) { System.out.println("链表为空"); return; } HeroNode2 temp = head.next; boolean flag = false;//判断是否找到需要删除结点的前一个结点 while(true) { if(temp == null) { break;//表示链表已经遍历结束 } if(temp.no==no) {//找到了需要删除的结点 flag = true; break; } temp=temp.next; } if(flag) {//temp为被删除结点的上一个结点,temp.next为被删除结点,temp.next.next为被删除结点的下一个结点 temp.pre.next=temp.next; //这里有个问题:如果要删除的结点是最后一个结点,那么temp.next.pre则无法执行,所以要进行一个判断 if(temp.next!=null) { temp.next.pre=temp.pre; } }else { System.out.println("没有找到要删除的结点"); } } } //创建一个结点 class HeroNode2{ public int no;//英雄的编号 public String name;//英雄的名字 public String nickname;//英雄的昵称 public HeroNode2 next;//指向下一个结点 public HeroNode2 pre;//指向前一个结点 //构造器 public HeroNode2(int hno,String hname,String hnickname) { this.no=hno; this.name=hname; this.nickname=hnickname; } //为了显示方法,重写toString @Override public String toString() { return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]"; } }
相关文章推荐
- Java数据结构和算法——数组、单向链表、双向链表
- Java数据结构和算法——数组、单向链表、双向链表
- Java数据结构和算法之双向链表
- 微软算法100题01 二叉搜索树转为双向链表
- 数据结构和算法-009 双向链表
- 修改自linux内核的双向循环链表通用算法
- 数据结构与算法--双向链表和双向循环链表
- 数据结构与算法之双向链表
- 把二元查找树转变成排序的双向链表——精选微软经典的算法面试100题中第一题
- 笔试算法题(05):转换BST为双向链表 & 查找栈中的最小元素
- 设以带头结点的双向循环链表表示的线性表L= (a1,a2,…,an),试写一时间复杂度O(n)的算法,将L改造为 (a1,a3,…,an,…,a4,a2)。
- C++类模板 实现双向循环链表的基本算法 《数据结构》(C++版 北京科海)中摘抄
- 微软等数据结构+算法面试100题(43)-- 把二元查找树转变成排序的双向链表
- 【老鸟学算法】二元查找树转变成排序的双向链表——算法思想及java实现
- 数据结构与算法笔记 lesson8 双向链表
- Python算法练习--把搜索树转成双向链表
- python实现·数据结构与算法之双向循环链表
- 每日一道算法题1 ——把二元查找树转变成排序的双向链表
- 算法1(单链表,环形队列,稀疏数组,双向链表,单向环形列表(约瑟夫问题))