推荐学习资料: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汉诺塔问题也是程序设计中的经典递归问题。