数据结构与算法_链表_双向链表和环形链表

1、双向链表和单向链表之间有什么区别?

答:双向链表和单向链表之间最大的区别就是其多了一个指向前一个节点的指针域。

2、双向链表对比于单链表有什么优点?

答:

  • (1)单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。 2)单向链表不能自我删除,需要靠辅助节点
  • (2)而双向链表,则可以自我删除,所以前面我们单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点(认真体会).

3、双向链表功能实现时和单向链表有何区别?

答:具体功能实现大体上没有区别,在遍历节点和修改节点两个功能上只需要将节点修改为双向节点,根本不需要进行其他改动。其次在增加节点和删除节点时可以直接指向目标节点后再进行操作。

具体实现代码:

package com.xiaofan.LinkedList;

public class DoubleLinkedListDomo {

	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 dou = new DoubleLinkedList();
		dou.addbyOrder(hero1);
		dou.addbyOrder(hero3);
		dou.addbyOrder(hero4);
		dou.addbyOrder(hero2);

		// 遍历
		dou.show();
		// 修改
		HeroNode2 newheroNode = new HeroNode2(4, "公孙胜", "入云龙");
		dou.updata(newheroNode);
		System.out.println("修改后");
		dou.show();
		// 删除节点
		System.out.println("删除吴用:---------");
		dou.delete(3);
		dou.show();
		// 添加节点
		HeroNode2 hero5 = new HeroNode2(5, "李逵", "黑旋风");
		System.out.println("找回吴用:----------");
		dou.add(hero3);
		dou.show();
	}

}

//创建一个双向链表的类

class DoubleLinkedList {
	// 先初始化一个头结点,头结点不动,不存放具体数据
	private HeroNode2 head = new HeroNode2(0, "", "");

	// 返回头节点
	public HeroNode2 getHead() {
		return head;
	}

	// 遍历双向链表
	// 显示链表
	public void show() {
		// 判断链表是否为空
		if (head.next == null) {
			System.out.println("链表为空");
			return;
		}
		// 使用temp遍历链表
		HeroNode2 temp = head.next;
		while (true) {
			// 判断是否到最后
			if (temp == null) {
				break;
			}
			// 输出节点信息
			System.out.println(temp);
			temp = temp.next;
		}
	}

	// 添加节点
	public void add(HeroNode2 heroNode) {
		// 因为head不能动,创建一个辅助节点temp
		HeroNode2 temp = head;
		// 遍历链表,找到最后
		while (true) {
			// temp.next==null,则找到最后
			if (temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		// 退出循环时,temp就指向了链表的最后
		// 形成双向链表
		temp.next = heroNode;
		heroNode.pre = temp;
	}

	//按顺序添加
		public void addbyOrder(HeroNode2 heroNode) {
			//因为只有向后的指针,所以找添加位置的前一个节点,才能插入
			HeroNode2 temp = head;
			boolean flag = false;
			while(true) {
				if(temp.next==null) {//说明已经到最后了,必须跳出循环
					break;
				}
				if(temp.next.no > heroNode.no) {//位置找到了,即找到第一个大于插入节点编号的节点
					break;
				}else if(temp.next.no == heroNode.no) {//说明编号已经存在
					flag=true;
					break;
				}
				temp=temp.next;
			}
			//判断flag的值
			if(flag) {//说明重复插入
				System.out.printf("重复插入%d节点",heroNode.no);
			}
			else {
				//可以插入
				heroNode.next=temp.next;//temp.next有可能是null
				temp.next=heroNode;
				heroNode.pre=temp;
				//如果要调用现在的heroNode.next一定要记得加一个判断条件
				if(heroNode.next!=null)
					heroNode.next.pre=heroNode;
			}
		}

	// 修改一个节点的内容
	// 双向链表的修改操作和单向链表的修改基本一样,只是节点的类型不一样
	public void updata(HeroNode2 newheroNode) {
		// 判断链表是否为空
		if (head.next == null) {
			System.out.println("链表为空");
			return;
		}
		// 找到需要修改的节点,根据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.nikeName = newheroNode.nikeName;
		} else {
			System.out.printf("没有找到编号为%d的节点\n", newheroNode.no);
		}
	}

	// 删除节点
	// 说明:对于双向链表,可以直接找到要删除的节点
	// 找到后,自我删除即可
	public void delete(int no) {

		if (head.next == null) {
			System.out.println("链表为空,无法删除");
			return;
		}

		// 找到需要删除的节点,根据no编号
		// 定义一个辅助变量
		HeroNode2 temp = head.next;// 因为可以找到要删除的节点,可以直接从第一个有效节点开始
		boolean flag = false;// 表示是否找到该节点
		while (true) {
			if (temp == null) {// 到链表最后节点的next
				break;
			}
			if (temp.no == no) {// 找到了要删除的节点的前一个节点
				flag = true;
				break;
			}
			temp = temp.next;// 后移遍历
		}
		// 根据flag 判断是否找到需要删除的节点
		if (flag) {
			// temp.next = temp.next.next;(单向链表的删除思路)
			temp.pre.next = temp.next;// 向前的指针
			// 这里有风险,有可能是最后一个节点
			// 如果是最后一个节点就不需要指向这句话,否则出现空指针
			if (temp.next != null) {
				temp.next.pre = temp.pre;
			}
			temp.pre = null;
			temp.next = null;

		} else {
			System.out.printf("没有找到要删除的编号为%d的节点\n", no);
		}

	}

}

//定义HeroNode2节点,每个HeroNode对象就是一个节点
class HeroNode2 {
	public int no;
	public String name;
	public String nikeName;
	public HeroNode2 pre;// 默认为null
	public HeroNode2 next;

	// 构造器
	public HeroNode2(int no, String name, String nikeName) {
		this.no = no;
		this.name = name;
		this.nikeName = nikeName;
	}

	// 为了便于显示,重写toString
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nikeName=" + nikeName + ']';
	}
}
发布了27 篇原创文章 · 获赞 2 · 访问量 680

猜你喜欢

转载自blog.csdn.net/qq_44273739/article/details/104954210