zoukankan      html  css  js  c++  java
  • java数据结构与算法三: 链表(双向链表)

    链表:双链表

    一、 双向链表的操作分析和实现

    (使用带head头的双向链表实现 —— 水浒英雄排行榜)

    1、管理单项链表的缺点分析:

    • 单项链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找
    • 单项链表不能自我删除,需要靠辅助节点,而双向链表,可以自我删除,所以单链表删除节点时,总是找到temp,temp是待删除节点的前一个节点

    2、双向链表完成遍历、添加、修改和删除的思路:

    1. 遍历:和单链表一样,只是可以向前,也可以向后查找
    2. 添加:(默认添加到双向链表的最后)
      • 先找到双向链表的最后这个节点
      • temp.next = newHeroNode
      • newHeroNode.pre = temp
    3. 修改与单链表一样
    4. 删除
      • 因为是双向链表,因此可以实现自我删除某个节点
      • 直接找到要删除的这个节点,比如temp
      • temp.pre.next = temp.next
      • temp.next.pre = temp.pre

    二、代码实现

    public class DoubleLinkedListDemo {
    
    	public static void main(String[] args) {
    		// 测试
    		System.out.println("双向链表的测试");
    		
    		//先创建节点
    		HeroNode2 hero1 = new HeroNode2(1,"宋江","及时雨");
    		HeroNode2 hero2 = new HeroNode2(2,"卢俊义","玉麒麟");
    		HeroNode2 hero3 = new HeroNode2(3,"吴用","智多星");
    		HeroNode2 hero4 = new HeroNode2(4,"林冲","豹子头");
    		
    		//创建一个双向链表
    		DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
    //		doubleLinkedList.add(hero1);
    //		doubleLinkedList.add(hero2);
    //		doubleLinkedList.add(hero3);
    //		doubleLinkedList.add(hero4);
    		doubleLinkedList.addByOrder(hero1);
    		doubleLinkedList.addByOrder(hero4);
    		doubleLinkedList.addByOrder(hero3);
    		doubleLinkedList.addByOrder(hero2);
    
    		doubleLinkedList.list();
    		
    		//修改
    		HeroNode2 hero5 = new HeroNode2(4,"公孙离","射手");
    		doubleLinkedList.update(hero5);
    		System.out.println("修改后的链表情况");
    		doubleLinkedList.list();
    		
    		//删除
    		doubleLinkedList.del(3);
    		System.out.println("删除后的链表情况--");
    		doubleLinkedList.list();
    	}
    
    }
    
    //创建一个双向链表的类
    class DoubleLinkedList {
    	
    	//先初始化一个头节点,头节点不要动
    	private HeroNode2 head = new HeroNode2(0,"","");
    	
    	//返回头节点
    	public 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 = temp.next;
    		}
    		//当退出while循环时,temp就指向了链表的最后
    		//形成一个双向链表
    		temp.next = heroNode;
    		heroNode.pre = temp;
    	}
    	
    	//第二种添加方式:按照编号添加到指定位置
    	public void addByOrder(HeroNode2 newHeroNode) {
    		HeroNode2 temp = head;
    		boolean flag = false;
    		while(true) {
    			if(temp.next == null) {
    				break;
    			}
    			//判断位置
    			if(temp.next.no > newHeroNode.no) {
    				break;
    			}else if(temp.next.no == newHeroNode.no) {
    				//编号重复
    				flag = true;
    				break;
    			}
    			temp = temp.next;
    		}
    		if(flag) {
    			System.out.printf("准备插入的英雄的编号%d已经存在,不能加入
    ",newHeroNode.no);
    		}else {
    			if(temp.next == null) {
    				temp.next = newHeroNode;
    				newHeroNode.pre = temp;
    			}else {
    				temp.next.pre = newHeroNode;
    				newHeroNode.next = temp.next;
    				temp.next = newHeroNode;
    				newHeroNode.pre = temp;
    				
    			}
    		}
    	}
    	
    	//修改一个节点的内容,双向链表的节点内容修改和单向链表一样
    	//只是节点的类型改成HeroNode2
    	public void update(HeroNode2 newHeroNode) {
    		//判断是否为空
    		if(head.next == null) {
    			System.out.println("链表为空");
    		}
    		//找到需要修改的节点,根据 no编号
    		//先定义一个辅助变量
    		HeroNode2 temp = head.next;
    		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);
    		}
    	}
    	
    	//从双向链表中删除一个节点
    	/**
    	 * 说明:
    	 * 1、对于双向链表,我们可以直接找到要删除的这个节点
    	 * 2、找到后,自我删除即可
    	 * @param no
    	 */
    	public void del(int no) {
    		
    		//判断当前链表是否为空
    		if (head.next == null) {
    			System.out.println("链表为空,无法删除");
    			return;
    		}
    		
    		HeroNode2 temp = head.next;
    		boolean flag = false;	// 标志是否找到待删除的节点
    		while(true) {
    			if(temp.next == null) {
    				//已经到链表的最后
    				break;
    			}
    			if(temp.no == no) {
    				//找到待删除的节点temp
    				flag = true;
    				break;
    			}
    			temp = temp.next;
    		}
    		//判断flag
    		if(flag) {
    			//找到,可以删除
    			temp.pre.next = temp.next;
    			//如果是最后一个节点,就不需要执行下面这句话,否则出现空指针
    			if (temp.next != null) {				
    				temp.next.pre = temp.pre;
    			}
    		}else {
    			System.out.printf("要删除的%d节点不存在
    ",no);
    		}
    	}
    	
    }
    
    //定义一个HeroNode,每个HeroNode,对象就是一个节点
    class HeroNode2 {
    	public int no;
    	public String name;
    	public String nickname;
    	public HeroNode2 next;	//指向下一个节点,默认为null
    	public HeroNode2 pre;	//指向前一个节点,默认为null
    	
    	//构造器
    	public HeroNode2(int no, String name, String nickname) {
    		this.no = no;
    		this.name = name;
    		this.nickname = nickname;
    	}
    	
    	//为了显示方法,我们重写toString	
    	@Override
    	public String toString() {
    		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
    	}
    
    }
    
  • 相关阅读:
    整套的操作体系:三点看股法
    [Garmin]安卓版本2.35完美安装程序+地图+JVC+电子眼
    [Garmin]安卓版本2.35完美安装程序+地图+JVC+电子眼
    [凯立德]2015春季版C2739-M7L83-3521JON,已O+带3D+带路况
    [凯立德]2015春季版C2739-M7L83-3521JON,已O+带3D+带路况
    DirectX9:总结篇 异常错误检测
    Linux开发:论ffmpeg的使用
    VS的bug集锦
    牛客:脑筋急转弯的选择题
    剑指Offer:栈的压入/弹出序列
  • 原文地址:https://www.cnblogs.com/flypig666/p/13479478.html
Copyright © 2011-2022 走看看