Estructura de datos y algoritmo _ lista vinculada _ lista doblemente vinculada y lista circular vinculada

1. ¿Cuál es la diferencia entre una lista doblemente vinculada y una lista unidireccional?

Respuesta: La mayor diferencia entre una lista doblemente vinculada y una lista individualmente vinculada es que tiene un campo de puntero adicional que apunta al nodo anterior.

2. ¿Cuáles son las ventajas de las listas doblemente enlazadas en comparación con las listas enlazadas individuales?

Respuesta:

  • (1) Para una lista vinculada unidireccional, la dirección de búsqueda solo puede estar en una dirección, mientras que una lista vinculada bidireccional se puede buscar hacia adelante o hacia atrás. 2) La lista enlazada unidireccional no se puede eliminar por sí sola, necesita depender de nodos auxiliares
  • (2) La lista doblemente vinculada se puede eliminar por sí misma, por lo que cuando eliminamos el nodo en la lista individualmente vinculada, siempre encontramos temp, temp es el nodo anterior del nodo que se eliminará (experiencia seria).

3. ¿Cuál es la diferencia entre una lista vinculada bidireccional y una lista vinculada unidireccional?

Respuesta: La implementación de funciones específicas es básicamente la misma: en las dos funciones de atravesar nodos y modificar nodos, solo necesita modificar los nodos a nodos bidireccionales, y no son necesarios otros cambios. En segundo lugar, al agregar y eliminar nodos, puede apuntar directamente al nodo de destino y luego operar.

Código de implementación específico:

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 artículos originales publicados · elogiados 2 · visitas 680

Supongo que te gusta

Origin blog.csdn.net/qq_44273739/article/details/104954210
Recomendado
Clasificación