栈和队列

3.栈和队列

3.1栈:后进先出的线性表

​ 栈是一种只能在一端进行插入或删除操作的线性表。表中允许进行插入、删除操作的一端称为栈顶

​ 栈的修改是按照后进先出的原则进行的,栈又称为后进先出的线性表。

​ 栈顶的当前位置是动态的,栈顶的当前位置由一个称为栈顶指针的位置指示器指示。表的另一端称为栈底

​ 当栈中没有数据元素时,称为空栈

​ 栈的插入操作通常称为进栈,栈的删除操作通常 称为出栈

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wSGzsKn2-1609764859962)(E:\StudySource\数据结构\栈和队列\图像\栈的示意图.png)]

例3.1 设一个栈的输入序列为A,B,C,D,则借助一个栈所得到的输出序列不可能是    。
	(A) A,B,C,D	(B) D,C,B,A  
	(C) A,C,D,B	(D) D,A,B,C       
//D


     例3.2 已知一个栈的进栈序列是1,2,3,…,n,其输出序列是p1,p2,…,pn,若p1=n,则pi的值    。
	(A) i  		          (B) n-i  
	(C) n-i+1  		(D) 不确定
//C
ADT Stack {
      数据对象:
         D={ ai | ai ∈ElemSet, i=1,2,...,n,  n≥0 }
      数据关系:
         R1={ <ai-1, ai >| ai-1, ai∈D, i=2,...,n }
                   约定an 端为栈顶,a1 端为栈底。  

基本操作:
InitStack(&S)初始化栈
DestroyStack(&S)销毁栈
StackLength(S)获得栈长度
StackEmpty(S)判空
GetTop(S,&e)得到栈顶元素
ClearStack(&S)清空栈元素
Push(&s,e)进栈
Pop(&S,&e)出栈
StackTravers(S)遍历:从下往上
//----- 栈的顺序存储表示 -----
  #define  STACK_INIT_SIZE  100; 
  #define  STACKINCREMENT   10;  
  typedef struct {
    int  *base; //栈底   
    int  *top;  //栈顶
    int  stacksize;  // 栈大小 
  } SqStack;
 int InitStack (SqStack &S)
{// 构造一个空栈S
  S.base=(int*)malloc(STACK_INIT_SIZE*      sizeof(int));
   if (!S.base) exit (-2); //存储分配失败
   S.top = S.base;
   S.stacksize = STACK_INIT_SIZE;
   return 1;
}
 int ClearStack(SqStack &S)
 { /* 把S置为空栈 */
   S.top=S.base;
   return 1;
 }
 int StackEmpty(SqStack S)
 { /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
   if(S.top==S.base)
         return 1;
   else
         return 0;
 }
 int StackLength(SqStack S)
 { /* 返回S的元素个数,即栈的长度 */
   return S.top-S.base;
 }
 int  GetTop(SqStack S, int &e)
 {
   if(S.top>S.base)
   {
     e=*(S.top-1);
     return 1;
   }
   else
     return 0;
 }
 int Push (SqStack &S, SElemType e) {
   if (S.top - S.base >= S.stacksize) {//栈满,追加存储空间
      S.base = (ElemType *) realloc ( S.base,
                (S.stacksize + STACKINCREMENT) * 
                                                      sizeof (int));
       if (!S.base) exit (OVERFLOW); //存储分配失败
       S.top = S.base + S.stacksize;
       S.stacksize += STACKINCREMENT;
   }
   *S.top++ = e;
    return 1;
}
int Pop (SqStack &S, int &e) {
     // 若栈不空,则删除S的栈顶元素,
     // 用e返回其值,并返回 1;
     // 否则返回 0
    if (S.top == S.base) return 0;
    S.top--;
    e = *S.top;
    return 1;
}
 int  StackTraverse(SqStack S)
 { int  *p; 
   p=S.base;
   while(p
3.2栈的应用举例
3.2.1数制转换

十进制数N----->d进制数的原理:

N = (N div d)*d + N mod d

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rh19nu1N-1609764859966)(E:\StudySource\数据结构\栈和队列\图像\数制转换.png)]

	public static int transformation(int number) {
     
		Stack<Integer> s = new Stack<Integer>();
		while(number != 0) {
     
			s.push(number % 8);//将余数入栈
			number /= 8;//除模
		}
		
		int result = 0;
		while(s.size() != 0) {
     
			//System.out.println(s.pop());
			result += s.pop() * Math.pow(10, s.size());//出栈并拼接数值
		}
		return result;
	}
3.2.2判断字符串是否对称(回文)
import java.util.Stack;

/*
 * 字符串是否回文
 */
public class StringSymmetric {
     

	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		System.out.println(stringSymmetric("123456654321"));
	}
	public static boolean stringSymmetric(String s) {
     
		//1.如果字符串为空,或者长度不大于1,返回false(不回文)
		if(s==null || s.length() <=1) {
     
			return false;
		}
		
		Stack<Character> stack  = new Stack<Character>();
		//2.字符串转换成字符数组
		char [] c = s.toCharArray();
		
		//3.字符数组单个入栈
		for(char cc:c) {
     
			stack.push(cc);
		}
		
		//4.字符数组出栈(即为反向输出),逐个对比,如果有不一致,返回false
		for(char cc:c) {
     
			if(cc != stack.pop())
				return false;
		}
        
		//5.如果第四步正常结束,此时字符串回文,返回true
		return true;
	}
}
3.2.3行编辑程序问题
import java.util.Scanner;
import java.util.Stack;

/*
 * 在用户输入一行的过程中,允许用户输入出差错,并在发现有误时可以及时更正。
 * 合理的做法:
 * 		        设立一个输入缓冲区,
 * 				用以接受用户输入的一行字符,
 * 				然后逐行存入用户数据区,
 * 				并假设“#”为退格符,“@”为退行符。
 * 假设从终端接受了这样两行字符:
 * 		whli##ilr#e(s#*s)
 * 		outcha@putchar(*s=#++);
 * 则实际有效的是下列两行:
 *      while (*s)
 *      putchar(*s++);
 *
 */

public class EditTransformation {

	public static void main(String[] args) {
		//定义输入工具类对象
		Scanner reader = new Scanner(System.in);
		System.out.println("请输入:");
		System.out.println(transformation(reader.next()));
	}
	
	public static String transformation(String s) {
		//1.声明栈
		Stack stack = new Stack();
		//2.生成字符数组
		char [] c = s.toCharArray();
		//3.遍历字符数组,对输入的字符串信息进行处理
		for(char cc:c) {
			//当遇到回车换行字符时,表示输入结束
			if(cc=='\n') {
				break;
			}
			//如果没有结束,根据不同的字符对栈进行不同的操作
			//@删除栈顶元素
			//#清空栈
			//default入栈
			switch(cc) {
			case '@':{//如果栈不为空,输出栈顶
				if(stack.size()!=0) {
					stack.pop();
					break;
					}
				}
			case '#':{
				stack.clear();
				break;
				}
			default:{
				stack.push(cc);
				break;
				}
			}
		}
		
		//4.从栈底到栈顶遍历
		String result = "";
		for(int i = 0; i < stack.size();i++) {
			result += stack.get(i);
		}
		
		return result;
	}
}

3.2.4表达式求值
package com.gavin.stack;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;

public class ExcepssionGetEvaluation {
     
	/**
	 * 存放数值的栈
	 */
	private static Stack<Float> numberStack = new Stack<Float>();
	
	/**
	 * 存放运算符的栈
	 */
	private static Stack<String> andCalcStack = new Stack<String>();
	
	/**
	 * 运算符优先级map集合
	 */
	private static final Map<String,Integer> OPT_PRIORITY_MAP = new HashMap<String,Integer>(){
     
		{
     
			put("(",0);
			put("+",2);
			put("-",2);
			put("*",3);
			put("/",3);
			put(")",7);
			put("=",20);
		
		}	
	};
	
	/**
	 * 如果栈顶元素是“=”,直接入栈
	 * 运算符优先级比较,当前运算符和栈顶运算符优先级对比,
	 * 如果大于栈顶元素优先级,可以入栈
	 * 执行一次运算,然后递归继续判断
	 * @param currentAndCalc 当前运算符
	 */
	public static void compareAndCalc(String currentAndCalc){
     
		//出口
		//判断栈运算符栈是否还有其他运算符:如果栈顶为“=”直接跳出递归
		if(andCalcStack.peek().equals("=")) {
     
			andCalcStack.push(currentAndCalc);
			return;
		}
		
		//1.获取当前栈顶运算符的优先级值
		int value = OPT_PRIORITY_MAP.get(andCalcStack.peek());
		
		//2.根据优先级进行不同的操作
		//如果优先级大于栈顶元素优先级,运算符入栈
		if(OPT_PRIORITY_MAP.get(currentAndCalc) > value) {
     
			andCalcStack.push(currentAndCalc);
		}
		//如果优先级小于或等于栈顶元素优先级,执行一次二元运算
		else {
     
			//将运算结果入栈
			numberStack.push(calculate());
			//执行递归继续判断
			compareAndCalc(currentAndCalc);
		}
	} 
	
	
	/**
	 * 判断字符串是否是数值,如果能转换成数值型,
	 * 返回数值,抛出异常代表转换失败,不是数值,返回-1
	 * @param token 当前字符串
	 * @return	数值,为-1表示不是数值
	 */
	public static float isNumber(String token) {
     
		//将字符串转换成数值,如果不抛出异常表示是数,否则不是数值
		try {
     
			float f = Float.parseFloat(token);
			return f;
		}
		catch (Exception e) {
     
			return -1.0f;
		}
	}
	
	/**
	 * 进行四则运算,根据不同运算符,执行不同的操作
	 * 在除法运算时,分母为0时,抛出异常,分母不能为0
	 * @return 运算结果
	 */
	public static float calculate() {
     
		try {
     
			//获得运算符
			String andCalc = andCalcStack.pop(); 
			//获得第二个运算数
			float b = numberStack.pop();
			//获得第一个运算数
			float a = numberStack.pop();
		
			if(andCalc.equals("+")) {
     
				return a + b;
			}
			else if(andCalc.equals("-")) {
     
				return a - b;
			}
			else if(andCalc.equals("*")) {
     
				return a * b;
			}
			else{
     
				if(b==0.0f) {
     
					throw new RuntimeException("表达式有误,分母不能为0!");
				}
				return a / b;
			}
		}
		catch (Exception e) {
     
			System.out.println("运算出现错误,请检查表达式是否有误!");
		}
		return 0.0f;
	}
	
	/**
	 * 将表达式字符串切割成字符数组
	 * @param input
	 * @return 字符串数组
	 */
	public static String[] getInput(String input) {
     
		
		//1.切割表达式字符串,如果抛出异常,提示输入有误
		try {
     
			String [] inputSplits = input.split(" ");
			
			//2.遍历字符串数组,输出表达式
			System.out.print("运算表达式:");
			for(String s:inputSplits) {
     
				System.out.print(s+" ");
			}
			System.out.println();
			
			//3.返回运算表达式数组
			return inputSplits;
		}
		catch(Exception e){
     
			System.out.println("输入有误,程序终止!!!");
			System.exit(-1);//终止运行
		}
		return null;
	}
	
	/**
	 * 计算表达式的值,使用两个栈:数值栈和运算符栈
	 * @param express 表达式字符数组
	 * @return 运算结果
	 */
	public static float canculate(String [] expression) {
     
		
		//2.遍历表达式数组,完成运算
		for(String s:expression) {
     
			//如果是数值,放入值栈中
			if(isNumber(s) != -1.0) {
     
				numberStack.push(isNumber(s));
			}
			//否则就是运算符
			//判断运算符的类型,执行不同的操作
			else {
     
				if(s.equals("(")) {
     
				//当前运算符是左括号,直接入栈
					andCalcStack.push("(");
				}
				else if(s.equals(")")) {
     
					//如果是右括号,递归计算,知道遇到左括号为止
					directCalc();
				}
				else {
     
					//正常运算符,判断如何入栈
					compareAndCalc(s);
				}
			}
		}
		
		//3.当遍历完表达式数组后,判断是否运算结束
		//如果栈顶不是等号,表示运算没有完成使用while循环继续运算,
		//遇到等号结束
		while(!andCalcStack.peek().equals("=")) {
     
			//计算结果入栈
			numberStack.push(calculate());
		}
		
		//4.循环结束时,运算完成,返回运算结果
		return numberStack.peek();
	}
	
	/**
	 *寻找左括号递归运算 
	 */
	public static void directCalc() {
     
		//1.遇到左括号,左括号出栈,递归终止
		if(andCalcStack.peek().equals("(")) {
     
			andCalcStack.pop();//删除栈顶左括号
		}
		//2.否则执行四则运算
		else {
     
			//将运算结果入栈
			numberStack.push(calculate());
			//执行递归继续判断是否继续运算
			directCalc();
		}
	}
	
	
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
//		try {
     
//			System.out.println(calculate(5, 0, "/"));
//		}
//		catch (Exception e) {
     
//			System.out.println(e);
//		}
		Scanner reader = new Scanner(System.in);
		System.out.print("请输入表达式(数值字符之间用空格隔开):");
		String input = reader.nextLine();
		
		
		andCalcStack.push("=");
		
		//计算获得结果
		float result = canculate(getInput(input));
		System.out.println("运算结果:" + result);
		
	}
}
3.2.5实现递归

1.当在一个函数的运行期间调用另一个函数时,在运行该被调用函数之前,
需先完成三项任务:

[1].将所有的实在参数、返回地址等信息传递给被调用函数保存;

[2].为被调用函数的局部变量分配存储区;

[3].将控制转移到被调用函数的入口;

2.从被调用函数返回调用函数之前,应该完成下列三项任务:

[1].保存被调函数的计算结果

[2].释放被调函数的数据区

[3].依照被调函数保存的返回地址将控制转移到调用函数。

3.多个函数嵌套调用的规则是:

后调用先返回!

此时的内存管理试行**“栈式管理”**:先调用的后返回,后调用的先返回。

1.打印输出所有四位二进制数
package com.gavin.stack;

public class AllFourSiteOfBinary {
     

	/**
	 * 二进制数字符表示数组
	 */
	private static char [] s = new char[5];
	
	/**
	 * 纪录总数
	 */
	private static int sum = 0;
	
	/**
	 * 递归函数
	 * @param n 当前第几位数字
	 */
	public void fun(int n) {
     
		if(n==4){
     
			print();
		}
		else {
     
			//递归当前位为0的所有结果
			s[n] = '0'; 
			fun(n+1);
			//递归当前位为1的所有结果
			s[n] = '1';
			fun(n+1);
		}
	}
	
	/**
	 * 打印输出
	 */
	public void print() {
     
		for(int i = 0; i < s.length;i++) {
     
			System.out.print(s[i]);
		}
		sum++;
	}
	
	/**
	 * 主函数
	 * @param args
	 */
	public static void main(String[] args) {
     
		
		s[4] = '\n';//用于回车换行打印
		AllFourSiteOfBinary allFourSiteOfBinary = new AllFourSiteOfBinary();
		allFourSiteOfBinary.fun(0);
		System.out.println("总共有"+sum+"个四位二进制数!");
	}
}
2.斐波那切数列
1,1,2,3,5,8,13,21,34,55,...

F 1 = F 2 = 1 ; F_1 = F_2 = 1; F1=F2=1;

F n = F ( n − 1 ) + F ( n − 2 ) , n > 2 ; F_n = F_(n-1) + F_(n-2),n >2; Fn=F(n1)+F(n2),n>2;

package com.gavin.stack;

public class FibonacciSequence {
     

	public int fun(int n) {
     
		if(n < 1) {
     
			return 0;
		}
		if(n==1 || n==2) {
     
			return 1;
		}
		else {
     
			return fun(n-1) + fun(n - 2);
		}
	}
	
	
	public static void main(String[] args) {
     
		FibonacciSequence fibonacciSequence = new FibonacciSequence();
		for(int i = 1; i <= 10; i++) {
     
			System.out.print(fibonacciSequence.fun(i)+"\t");
		}	
	}
}
3.2.6迷宫求解
0 0 0 0 0 0 0
0 1 1 1 0 0 0
0 1 0 1 1 0 0
0 1 1 0 1 0 0
0 1 1 1 0 0 0
0 0 0 1 1 1 0
0 0 0 0 0 0 0
package com.gavin.stack;
/*
 * 迷宫位置对象
 */
public class MazePath {
     
	private int x;//横坐标
	private int y;//纵坐标
	private int direction;//方向:1--上 2--右 3--下  4--左
	
	public int getX() {
     
		return x;
	}
	public void setX(int x) {
     
		this.x = x;
	}
	public int getY() {
     
		return y;
	}
	public void setY(int y) {
     
		this.y = y;
	}
	public int getDirection() {
     
		return direction;
	}
	public void setDirection(int direction) {
     
		this.direction = direction;
	}
	
	//打印信息
	public String toString() {
     
		String direction = "";
		if(this.direction == 0) {
     
			direction += "出口";
		}
		if(this.direction == 1) {
     
			direction += "向上走";
		}
		if(this.direction == 2) {
     
			direction += "向右走";
		}
		if(this.direction == 3) {
     
			direction += "向下走";
		}
		if(this.direction == 4) {
     
			direction += "向左走";
		}
		return "("+this.x+","+this.y+")"+direction;
	}
	
	/**
	 * 重写相等比较函数
	 */
	@Override
	public boolean equals(Object obj) {
     
		if(this == obj) {
     
			return true;
		}
		if(obj instanceof MazePath) {
     
			MazePath mazePath = (MazePath) obj;
			return mazePath.getX() == this.x && mazePath.getY() == this.y;
		}
		else {
     
			return false;
		}
	}
}
package com.gavin.stack;

import java.util.Stack;

/*
 * 走迷宫
 */

public class Maze {
     

	/**
	 * 迷宫路径栈
	 */
	public static Stack<MazePath> pathStack = new Stack<MazePath>();

	/**
	 * 迷宫数组
	 */
	public static int[][] maze = new int[7][7];

	/**
	 * 出口
	 */
	public static MazePath endMazePath = new MazePath();

	/**
	 * 入口
	 */
	public static MazePath startMazePath = new MazePath();

	public void initMaze() {
     
		// 0表示障碍,1表示通路
		// 创建一条通路
		maze[1][1] = 1;// 起点
		maze[2][1] = 1;
		maze[3][1] = 1;
		maze[3][2] = 1;
		maze[4][2] = 1;
		maze[4][3] = 1;
		maze[5][3] = 1;
		maze[5][4] = 1;
		maze[5][5] = 1;// 终点

		// 添加障碍
		maze[1][2] = 1;
		maze[1][3] = 1;
		maze[2][3] = 1;
		maze[2][4] = 1;
		maze[3][4] = 1;

		// 3.设置起点和终点
		// 设置起点
		startMazePath.setX(1);
		startMazePath.setY(1);

		// 设置终点
		endMazePath.setX(5);
		endMazePath.setY(5);
	}

	/**
	 * 打印迷宫
	 * 
	 * @param maze 迷宫数组
	 */
	public void print(int[][] maze) {
     
		for (int[] a : maze) {
     
			for (int i : a) {
     
				System.out.print(i + "\t");
			}
			System.out.println();
		}
	}

	/**
	 * 判断当前结点是否是出口
	 * 
	 * @param mazePath 当前结点
	 * @return 判断结果
	 */
	public boolean isEnd(MazePath mazePath) {
     
		if (mazePath == null) {
     
			return false;
		} else if (mazePath.getX() == endMazePath.getX() && mazePath.getY() == endMazePath.getY()) {
     
			return true;
		}
		return false;
	}

	/**
	 * 打印路径
	 */
	public void printPath() {
     
		// 从下往上打印输出
		for (int i = 0; i < pathStack.size(); i++) {
     
			// 打印结点信息
			System.out.println(pathStack.get(i).toString());
		}
	}

	/**
	 * 判断该节点是否已经来过
	 * 
	 * @param mazePath 结点
	 * @return 判断结果
	 */
	public boolean isRecord(MazePath mazePath) {
     
		if (pathStack.size() == 0) {
     
			return false;
		} else {
     
			return pathStack.contains(mazePath);
		}
	}

	/**
	 * 递归寻找正确的路径
	 * 
	 * @param mazePath 结点
	 */
	public void getPath(MazePath mazePath) {
     
		// 1.先判断是否在栈中存在,如果存在结束当前递归
		// 否则入栈
		if (isRecord(mazePath)) {
     
			mazePath.setDirection(0);
			return;
		} else {
     
			pathStack.push(mazePath);
		}

		// 2.递归出口:当前结点是出口
		if (isEnd(mazePath)) {
     
			printPath();
			return;
		}

		// 3.不是出口时,按情况递归
		int x = mazePath.getX();// 横坐标
		int y = mazePath.getY();// 纵坐标
		MazePath newMaze = new MazePath();

		// 往上走
		if (maze[x - 1][y] == 1) {
     
			// 设置方向
			mazePath.setDirection(1);
			// 设置新的横纵坐标
			newMaze.setX(x - 1);
			newMaze.setY(y);
			// 递归
			getPath(newMaze);
		}

		// 往右走
		if (maze[x][y + 1] == 1) {
     
			mazePath.setDirection(2);
			newMaze.setX(x);
			newMaze.setY(y + 1);
			getPath(newMaze);
		}

		// 往下走
		if (maze[x + 1][y] == 1) {
     
			mazePath.setDirection(3);
			newMaze.setX(x + 1);
			newMaze.setY(y);
			getPath(newMaze);
		}

		// 往左走
		if (maze[x][y - 1] == 1) {
     
			mazePath.setDirection(4);
			newMaze.setX(x);
			newMaze.setY(y - 1);
			getPath(newMaze);
		}

		// 如果前四个方向都走不通,会执行后退
		mazePath.setDirection(0);
		pathStack.pop();
	}

	/**
	 * 测试函数
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
     
		Maze mazeDemo = new Maze();
		// 1.初始化故宫
		mazeDemo.initMaze();

		// 2.打印迷宫
		mazeDemo.print(maze);

		// 3.调用递归函数寻找路径
		mazeDemo.getPath(startMazePath);
	}

}
3.3队列的类型定义

数据对象:

​ D={ai | ai∈ElemSet, i=1,2,…,n, n≥0}

数据关系:

​ R1={ | ai-1, ai ∈D, i=2,…,n}

​ 约定其中,a1端为队列头,an端为队列尾

基本操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sFzfatmK-1609764859970)(E:\StudySource\数据结构\栈和队列\图像\队列操作.png)]

3.4队列
package com.gavin.queue;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/*
 * 先进先出
 * 1.LinkedList类实现了接口Queue,所以队列的声明
 * 	Queue queue = new LinkedList();
 * 
 * 2.关于队列的几个常用操作:
 * 		2.1 boolean add(E e) 将指定的元素插入此队列(如果立即可行且不会违反容量限制),
 * 			在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。
 * 		2.2 boolean offer(E e) 将指定的元素插入此队列(如果立即可行且不会违反容量限制),
 * 			当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素返回false
 * 			,而只是抛出一个异常。
 * 		2.3 E element() 获取,但是不移除此队列的头。
 * 			此方法与 peek 唯一的不同在于:此队列为空时将抛出一个异常。 
 * 		2.4 E peek() 获取但不移除此队列的头;如果此队列为空,则返回 null。
 * 		2.5	E poll() 获取并移除此队列的头,如果此队列为空,则返回 null。
 * 		2.6 E remove() 获取并移除此队列的头。
 * 			此方法与 poll 唯一的不同在于:此队列为空时将抛出一个异常。
 *  
 * 3.方法对比
 * 		3.1 offer,add 区别:
 *		一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
 *		这时新的 offer 方法就可以起作用了。
 *		它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。
 *
 *		3.2 poll,remove 区别:
 *		remove() 和 poll() 方法都是从队列中删除第一个元素。
 *		remove() 的行为与 Collection 接口的版本相似, 
 *		但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。
 *		因此新的方法更适合容易出现异常条件的情况。
 *
 *		3.3 peek,element区别:
 *		element() 和 peek() 用于在队列的头部查询元素。
 *		与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。
 */
public class QueueDemo {
     
	public static Queue<Person> queue = new LinkedList<Person>();
	public static Queue<Person> queue2 = new LinkedList<Person>();

	public static void main(String[] args) {
     
		//1.boolean add(E e)
		Person p1 = new Person();
		p1.setAge(1);
		System.out.println(	queue.add(p1));
		System.out.println("**********************************************");
		
		//2.boolean offer(E e)
		Person p2 = new Person();
		p2.setAge(2);
		System.out.println(queue.offer(p2));
		System.out.println("**********************************************");
		
		//3.E element()
		System.out.println(queue.element().getAge());//1
		System.out.println(queue.element().getAge());//1
		//System.out.println(queue2.element());//抛出异常 java.util.NoSuchElementException
		System.out.println("**********************************************");
		
		//4.E peek()
		System.out.println(queue.peek().getAge());//1
		System.out.println(queue.peek().getAge());//1
		System.out.println(queue2.peek());//null
		System.out.println("**********************************************");
		
		//5.E poll()
		System.out.println(queue.poll().getAge());//1
		System.out.println(queue.poll().getAge());//2
		System.out.println(queue2.poll());//null
		System.out.println("**********************************************");
		
		//6.E remove()
		queue2.offer(p1);
		queue2.offer(p2);
		System.out.println(queue2.remove().getAge());//1
		System.out.println(queue2.remove().getAge());//2
		System.out.println(queue2.remove());//抛出异常 java.util.NoSuchElementException
	}
}
package com.gavin.queue;

import java.util.LinkedList;
import java.util.Queue;

/*
 * 设有n个人站成一排,从左向右的编号分别为1~n, 
 * 现在从左向右报数“1,2,1,2,1,2….”,数到”1”的人出列,
 * 数到”2”的人站到队伍最右边。报数过程反复进行,直到n个人都出列为止。
 */



public class NumberOff {
     

	/**
	 * 报数队列
	 */
	private static Queue<NumberQueue> numberStack = new LinkedList<NumberQueue>();
	
	/**
	 * 总人数
	 */
	private static int totalNumber = 15;
	
	/**
	 * 报数
	 */
	public void numberOff() {
     
		//记录当前栈中报数人数
		int number = numberStack.size();
		int k = 1;//标志奇数还是偶数,用于判断当前报数是1还是2
		int oneTwo = 0;
		//遍历队列
		
		for(int i = 0; i < number; i++) {
     
			//如果报数为1出列
			if(numberStack.peek().getOneTwo() == 1) {
     
				System.out.println("出列人序号:"+numberStack.poll().getNumber());
			}
			//否则报数为2,重新分配报数,走到队伍最右边
			else {
     
				if(k % 2 == 1) {
     
					oneTwo = 1;
				}
				else {
     
					oneTwo = 2;
				}
				numberStack.peek().setOneTwo(oneTwo);//重新分配报数
				NumberQueue newNumberQueue = numberStack.poll();//出队列
				numberStack.offer(newNumberQueue);//排到队列最右边
			}
		}
	}
	
	/**
	 * 初始化报数栈
	 */
	public void initStack() {
     
		int k = 1;//标志奇数还是偶数,用于判断当前报数是1还是2
		int oneTwo = 0;
		for(int i = 0; i < totalNumber; i++) {
     
			if(k % 2 == 1) {
     
				oneTwo = 1;
			}
			else {
     
				oneTwo = 2;
			}
			NumberQueue numberQueue = new NumberQueue(k, oneTwo);
			numberStack.offer(numberQueue);
			k++;
		}
	}
	
	
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		NumberOff numberOff = new NumberOff();
		
		numberOff.initStack();
		
		while(numberStack.size() != 0) {
     
			numberOff.numberOff();
		}
	}

}

你可能感兴趣的:(数据结构,笔记,栈,queue,stack)