栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

day7-Java(递归、链队列)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

day7-Java(递归、链队列)

day7-递归、链队列

递归

一、关于递归二、递归求和与斐波那契数列三、代码与运行结果总结 链队列

一、关于链队列二、链队列实现逻辑三、代码与数据测试总结

递归 一、关于递归

递归(Recursion)是指在函数的定义中使用函数自身的方法,通俗的说就是函数本身自己调用自己。格外重要的是,这个函数必须有明确的结束条件,否则就会导致无限递归的情况。如下:

public static int sumToN(int paraN) {
		// 结束条件
		if (paraN <= 0) {
			return 0;
		} // Of if 
		
		// 在函数中调用自己
		return sumToN(paraN - 1) + paraN; 
	} // Of sumToN

关于递归还需注意与循环的区别,递归顾名思义有一层一层往下的递,还有重要的归。当函数被调用时,它的变量空间是创建于运行时的堆栈上的,假定我以5这个值调用上述递归函数。堆栈内容如下表,栈顶位于最下方:

paraNsumToNreturn
第一次调用5sumToN(5)sumToN(4) + 5
第二次调用4sumToN(4)sumToN(3) + 4
第三次调用3sumToN(3)sumToN(2) + 3
第四次调用2sumToN(2)sumToN(1) + 2
第五次调用1sumToN(1)sumToN(0) + 1
第六次调用0sumToN(0)0

从上表的信息很容易看出,递归是如何将一个问题逐渐最小化解决的,从方法调用开始,函数return结果都会被压入栈,直到方法调用结束,最后从栈顶逐个返回得到结果。经过逐个代入,结果如下:

paraNsumToNreturn
0sumToN(0)0
1sumToN(1)0 + 1
2sumToN(2)0 + 1 + 2
3sumToN(3)0 + 1 + 2 + 3
4sumToN(4)0 + 1 + 2 + 3 + 4
5sumToN(5)0 + 1 + 2 + 3 + 4 + 5 = 15
二、递归求和与斐波那契数列

关于递归求和的体会在上段中已经作为例子详细阐述了,这段中就不再说明了。
斐波那契数列是指从第三项开始,每一项都等于前两项之和的这样一个数列(第一个和第二个数分别是1和1),可表示为如下形式: a n = a n − 1 + a n − 2 a_n = a_{n-1} + a_{n-2} an​=an−1​+an−2​显然这是一个线性递推数列。求N的斐波那契数列代码实现如下:

public static int fibonacci(int paraN) {
		if (paraN <= 0) {
			// Negative values are invalid. Index 0 corresponds to the first element 0.
			return 0;
		} if (paraN ==1 ) {
			// Basis.
			return 1;
		} // Of if
		
		return fibonacci(paraN - 1) + fibonacci(paraN - 2);
	} // Of fibonacci
三、代码与运行结果
package datastructure.stack;


public class Recursion {
	
	public static int sumToN(int paraN) {
		if (paraN <= 0) {
			// Basis.
			return 0;
		} // Of if 
		
		return sumToN(paraN - 1) + paraN;
	} // Of sumToN
	
	
	public static int fibonacci(int paraN) {
		if (paraN <= 0) {
			// Negative values are invalid. Index 0 corresponds to the first element 0.
			return 0;
		} if (paraN ==1 ) {
			// Basis.
			return 1;
		} // Of if
		
		return fibonacci(paraN - 1) + fibonacci(paraN - 2);
	} // Of fibonacci
	
	
	public static void main(String args[]){
		int tempValue = 5;
		System.out.println("0 sum to " + tempValue + " = " + sumToN(tempValue));
		tempValue = -1;
		System.out.println("0 sum to " + tempValue + " = " + sumToN(tempValue));
		
		for (int i = 0; i < 10; i++) {
			System.out.println("Fibonacci " + i + ": " + fibonacci(i));
		} // Of for i
	} // Of main
} // class Recursion

运行结果:

总结

递归算法的一个重要思路就是把规模大的问题转化为规模小的子问题来解决,这些问题的演化是一个从大到小,由近及远的过程,并且会有一个明确的终点(临界点),一旦到达了这个终点,就不用再往更小、更远的地方走下去。最后,从这个终点开始,原路返回到原点,原问题以此解决。
在初学递归时,容易分不清递归和循环,两者有一个显然的共同特点,即做重复任务,但递归通常很直白地描述一个问题的求解过程,如这段代码中求和函数里 sumToN(paraN - 1) + paraN,而使用循环的算法有时并不会那么清晰地描述解决问题的步骤。这两者是两种不同的解决问题的思路。递归的简洁与可读性是最大的优点,而其效率问题是难以避免的缺点。

链队列 一、关于链队列

链队列的实现并不难,与前两天写的链表结构相似。不同的是链队列不仅有头指针,还有链表没有的尾指针,且入队仅操作尾部,出队仅操作头部(队列特点,先进先出,后进后出)。

二、链队列实现逻辑

创建一个内嵌类,节点Node由一个需要存储的对象data以及对下个节点的引用组成。

class Node {
		int data;
		Node next;
		public Node(int paraValue) {
			data = paraValue;
			next = null;
		} // Of the constructor
	} // Of class Node

头尾两个指针

Node header;
Node tail;

构造一个空链队列,头指针和尾指针都指向头结点。

public linkedQueue() {
		header = new Node(-1);
		tail = header;
	} 

接下来就需要实现入队和出队的功能,参考前面链表部分的插入和删除操作,注意插入和删除分别在链队列的尾指针和头指针处进行。入队操作如下:
首先创建一个新的节点。

Node tempNode = new Node(paraValue);

然后将新节点插入到尾指针指向的节点之后,再使尾指针指向新节点,完成入队。

tail.next = tempNode;
tail = tempNode;

出队操作时,要检查队列是否为空,若为空,则无对象可出列。因为队列先进先出的特性,出队操作是在头指针指向的下一个节点处进行的,在进行几次出队操作后,若头指针指向的下一个节点为空,即只剩下头结点,则尾指针也指向头结点,即tail = header。

header.next = header.next.next;
三、代码与数据测试
package datastructure.queue;


public class linkedQueue {
	
	
	class Node {
		
		int data;

		
		Node next;

		
		public Node(int paraValue) {
			data = paraValue;
			next = null;
		} // Of the constructor
	} // Of class Node

	
	Node header;

	
	Node tail;

	
	public linkedQueue() {
		header = new Node(-1);
		// header.next = null;

		tail = header;
	} // Of the first constructor

	
	public void enqueue(int paraValue) {
		Node tempNode = new Node(paraValue);
		tail.next = tempNode;
		tail = tempNode;
	} // Of enqueue

	
	public int dequeue() {
		if (header == tail) {
			System.out.println("No element in the queue");
			return -1;
		} // Of if

		int resultValue = header.next.data;

		header.next = header.next.next;

		// The queue becomes empty.
		if (header.next == null) {
			tail = header;
		} // Of if

		return resultValue;
	} // Of dequeue

	
	public String toString() {
		String resultString = "";

		if (header.next == null) {
			return "empty";
		} // Of if

		Node tempNode = header.next;
		while (tempNode != null) {
			resultString += tempNode.data + ", ";
			tempNode = tempNode.next;
		} // Of while

		return resultString;
	} // Of toString

	
	public static void main(String args[]) {
		linkedQueue tempQueue = new linkedQueue();
		System.out.println("Initialized, the list is: " + tempQueue.toString());

		for (int i = 0; i < 5; i++) {
			tempQueue.enqueue(i + 1);
		} // Of for i 
		System.out.println("Enqueue, the queue is: " + tempQueue.toString());
		
		tempQueue.dequeue();
		System.out.println("Dequeue, the queue is: " + tempQueue.toString());
		
		int tempValue;
		for (int i = 0; i < 5; i++) {
			tempValue = tempQueue.dequeue();
			System.out.println("Looped delete " + tempValue + ", the new queue is: " + tempQueue.toString());
		} // Of for i
		
		for (int i = 0; i < 3; i++) {
			tempQueue.enqueue(i + 10);
		} // Of for i
		System.out.println("Enqueue, the queue is: " + tempQueue.toString());
	}// Of main
}// Of calss linkedQueue

运行结果:

总结

链队列可以动态的申请和释放空间,在入队操作时不用检测队列是否已满,这也是链队列相较于顺序表的优点。队列是顺序结构,其存储的数据一个挨着一个,链表则是相当于一根线把存储数据连接起来,不难看出,在查找上,队列肯定是优于链表的,而在删除和插入上,链表只需把连接的线剪断再在断处用新的接上,所以实现起来很快。

今日代码量:217
累积:1506

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/749277.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号