Data structure and algorithm _ linked list _ doubly linked list and circular linked list

1. What is the difference between a doubly linked list and a one-way linked list?

Answer: The biggest difference between a doubly linked list and a singly linked list is that it has an additional pointer field that points to the previous node.

2. What are the advantages of doubly linked lists compared to single linked lists?

answer:

  • (1) For a one-way linked list, the search direction can only be in one direction, while a two-way linked list can be searched forward or backward. 2) The one-way linked list cannot be deleted by itself, it needs to rely on auxiliary nodes
  • (2) The doubly linked list can be deleted by itself, so when we delete the node in the singly linked list, we always find temp, temp is the previous node of the node to be deleted (seriously experience)

3. What is the difference between a two-way linked list and a one-way linked list?

Answer: The implementation of specific functions is basically the same. In the two functions of traversing nodes and modifying nodes, you only need to modify the nodes to bidirectional nodes, and no other changes are necessary. Secondly, when adding and deleting nodes, you can directly point to the target node and then operate.

Specific implementation code:

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 + ']';
	}
}
Published 27 original articles · praised 2 · visits 680

Guess you like

Origin blog.csdn.net/qq_44273739/article/details/104954210