java版数据结构笔记5- 链表(LinkedList)

本文介绍了链表结构,包括单链表、循环链表和双向循环链表的定义、图示及实现代码,还展示了链表的删除操作。同时阐述了递归算法,给出使用递归解决斐波那契和汉诺塔问题的Java代码,并介绍了汉诺塔问题的简单操作方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  推荐学习资料:java中的链表结构

 定义:

    链表是一种物理存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

图示:

单链表:

链表删除操作:

循环链表:首尾引用互连即可

双链表与双向循环链表:相对于单向链表来说既要存储下一个节点的引用,还要存储上一个节点的引用

 双向链表的删除操作:

 递归算法:

汉诺塔问题:下文中有使用递归实现汉诺塔问题的Java代码

 

创建Node类实现单链表:

创建Node类:

/**
 * 节点
 * @author Mr.Cao
 *
 */
public class Node {
	
	/** 节点的值 */	
	int data;
	/** 下一个节点的应用 */
	Node next;

	
	public Node() {
		super();
	}
	
	/**
	 * 创建Node类,并初始化值
	 * @param data
	 */
	public Node(int data) {
		super();
		this.data = data;
	}
	
	/**
	 * 添加一个节点
	 * @param next
	 */
	public Node addNode(Node next) {
		
		if (this.next() == null) {
			this.next = next;
		} else {
			this.next().addNode(next);
		}
		
		return next;
	}
	
	/**
	 * 插入一个节点
	 * @param next
	 */
	public Node insertNode(Node next) {
		next.next = this.next();
		this.next = next;
		return next;
	}
	
	/**
	 * 获得下一个节点
	 * @return
	 */
	public Node next() {
		return this.next;
	}
	
	/**
	 * 获得节点的值
	 * @return
	 */
	public int getData() {
		return this.data;
	}
	
	/**
	 * 删除下一个节点
	 */
	public void removeNext() {
		if(this.next() != null) {
			this.next = this.next().next();
		}
	}
	
	/**
	 * 显示节点信息
	 */
	public void show() {
		Node currentNode = this;
		
		while(currentNode != null) {
			System.out.print("(" + currentNode.getData() + ") ---> ");
			currentNode = currentNode.next();
		}
		System.out.println();
	}
	
	
}

测试单链表:

public static void main(String[] args) {
		//创建多个节点,节点持有新的节点的引用形成链表
		Node n1 = new Node(1);//创建节点1
		Node n2 = new Node(2);//创建节点2
		Node n3 = new Node(3);//创建节点3
		
		n1.addNode(n2).addNode(new Node(4));//在链上添加节点2,节点4
		n1.show();//输出该节点所在整个链的信息
		
		n1.addNode(n3);//在链上添加节点3
		n1.show();//输出该节点所在整个链的信息

		System.out.println(n1.next().getData());//输出节点的下一个节点
		
		n1.show();//输出该节点所在整个链的信息

		n1.removeNext();//删除下一个节点
		n1.show();//输出该节点所在整个链的信息
		
		n1.insertNode(new Node(5));//插入一个新的节点
		n1.show();//输出该节点所在整个链的信息
	}

输出:

(1) ---> (2) ---> (4) --->
(1) ---> (2) ---> (4) ---> (3) --->
2
(1) ---> (2) ---> (4) ---> (3) --->
(1) ---> (4) ---> (3) --->
(1) ---> (5) ---> (4) ---> (3) --->

改写单链表实现循环链表:

循环链表的节点如下:

/**
 * 循环链表
 * @author Mr.Cao
 *
 */
public class LoopNode {
	
	/** 当前节点的值 */	
	int data;
	/** 下一个节点的引用 */
	LoopNode next = this;
	
	public LoopNode() {
		super();
	}

	public LoopNode(int data) {
		super();
		this.data = data;
	}
	 
	
	/**
	 * 插入一个节点
	 * @param next
	 */
	public LoopNode insertNode(LoopNode next) {
		next.next = this.next();
		this.next = next;
		return next; 
	}
	
	/**
	 * 获得下一个节点
	 * @return
	 */
	public LoopNode next() {
		return this.next;
	}
	
	/**
	 * 获得节点的值
	 * @return
	 */
	public int getData() {
		return this.data;
	}
	
	/**
	 * 删除下一个节点
	 */
	public void removeNext() {
		if(this.next() != null) {
			this.next = this.next().next();
		}
	}
	
	/**
	 * 显示节点信息
	 */
	public void show() {
		LoopNode currentNode = this;

		do {
			System.out.print("(" + currentNode.getData() + ") ---> ");
			currentNode = currentNode.next();
		
			if(currentNode == this) {
				break;
			}
			
		} while(true);
		System.out.println();
	}
	
	
}

测试:

public static void main(String[] args) {
		
		//测试循环链表
		LoopNode l1 = new LoopNode(1);
		LoopNode l2 = new LoopNode(2);
		LoopNode l3 = new LoopNode(3);
		LoopNode l4 = new LoopNode(4);
		LoopNode l5 = new LoopNode(5);
		
		l1.insertNode(l2).insertNode(l3).insertNode(l4).insertNode(l5);
		l1.show();
		l2.insertNode(new LoopNode(6));
		l1.show();
	}

输出:

(1) ---> (2) ---> (3) ---> (4) ---> (5) --->
(1) ---> (2) ---> (6) ---> (3) ---> (4) ---> (5) --->

改写单链表实现双向循环链表:

双链表的节点如下:此处为循环双向链表

/**
 * 循环双链表
 * @author Mr.Cao
 *
 */
public class DoubleNode {
	/** 当前节点的值 */	
	int data;
	/** 下一个节点的引用 */
	DoubleNode next = this;
	/** 上一个节点的引用 */ 
	DoubleNode pre = this;
	
	public DoubleNode() {
		super();
	}

	public DoubleNode(int data) {
		super();
		this.data = data;
	}
	 
	
	/**
	 * 插入一个节点
	 * @param next
	 */
	public DoubleNode insertNode(DoubleNode next) {
		next.pre = this;
		next.next = this.next();
		this.next = next;	
		
		if(this.pre.equals(this)) {
			this.pre = next;
		}
		return next; 
	}
	
	/**
	 * 获得下一个节点
	 * @return
	 */
	public DoubleNode next() {
		return this.next;
	}
	
	/**
	 * 获得上一个节点
	 * @return
	 */
	public DoubleNode pre() {
		return this.pre;
	}
	
	/**
	 * 获得节点的值
	 * @return
	 */
	public int getData() {
		return this.data;
	}
	
	/**
	 * 删除下一个节点
	 */
	public void removeNext() {
		if(this.next() != null) {
			this.next = this.next().next();
		}
	}
	
	/**
	 * 显示节点信息
	 */
	public void show() {
		DoubleNode currentNode = this;

		do {
			System.out.print("(" + currentNode.getData() + ") ---> ");
			currentNode = currentNode.next();
		
			if(currentNode == this) {
				break;
			}
			
		} while(true);
		System.out.println();
	}
	
	
}

测试循环双链表:

public static void main(String[] args) {

		//测试循环双链表
		DoubleNode d1 = new DoubleNode(1);
		DoubleNode d2 = new DoubleNode(2);
		DoubleNode d3 = new DoubleNode(3);
		

		d1.show();
		d1.insertNode(d2);
		d1.insertNode(d3);
		d1.show();
		
	}

输出:

(1) --->
(1) ---> (3) ---> (2) --->

 

递归算法:

递归实现从1加到100:
public static void print(int i) {
		if(i < 100) {
			System.out.println(i);
			print(++i);
		}
	}

递归解决斐波那契:

public static int Fibonacci(int i) {
		if(i == 1 || i == 2) {
			return 1;
		} else {
			return Fibonacci(i - 1) + Fibonacci(i - 2);
		}
	}

递归解决汉诺塔问题:

public void 汉诺塔(int n, String A柱, String B柱, String C柱) {
	if (n == 1) {
		输出文字("把第【" + n + "】号盘从【" + A柱 + "】移到【" + C柱 + "】");
	} else {
		汉诺塔(n - 1, A柱, C柱, B柱);
		输出文字("把第【" + n + "】号盘从【" + A柱 + "】移到【" + C柱 + "】");
		汉诺塔(n - 1, B柱, A柱, C柱);
	}
}

int count = 0;
public void 输出文字(Object o) {
    System.out.println("步骤" + ++count + ": " + o);
}
汉诺塔(3, "A柱", "B柱", "C柱");

输出:

步骤1: 把第【1】号盘从【A柱】移到【C柱】
步骤2: 把第【2】号盘从【A柱】移到【B柱】
步骤3: 把第【1】号盘从【C柱】移到【B柱】
步骤4: 把第【3】号盘从【A柱】移到【C柱】
步骤5: 把第【1】号盘从【B柱】移到【A柱】
步骤6: 把第【2】号盘从【B柱】移到【C柱】
步骤7: 把第【1】号盘从【A柱】移到【C柱】

拓展资料:

汉诺塔其实算法非常简单,当盘子的个数为n时,移动的次数应等于2^n – 1(有兴趣的可以自己证明试试看)。后来一位美国学者发现一种出人意料的简单方法,只要轮流进行两步操作就可以了。首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上,根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;

若n为奇数,按顺时针方向依次摆放 A C B。1.按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。2.接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘。这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。

3.反复进行⑴⑵操作,最后就能按规定完成汉诺塔的移动。所以结果非常简单,就是按照移动规则向一个方向移动金片:如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C汉诺塔问题也是程序设计中的经典递归问题。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值