数据结构(二)栈和队列

一、概述

栈和队列是数组和链表的高级封装的数据结构。

栈和队列的重点在其结构特性,栈和队列的底层不论是数组实现还是链表实现都不重要,因为同属于线性存储结构,可以通过数组实现一个栈结构,也可以使用链表实现一个栈结构,同样队列也是如此。

二、实现

2.1 栈

2.1.1栈结构的特点

  • 栈的结构特性是:元素先进后出(First In Last Out,简称FILO)
  • 我们将元素放入栈结构中的操作称之为元素入栈
  • 将元素从栈结构中取出的操作称之为元素出栈
  • 将最先进入栈结构中的元素称之为栈底元素,这个方向同时称之为栈底
  • 将最后进入栈结构中的元素称之为栈顶元素,这个方法同时称之为栈顶

2.1.2 Java中的栈结构:Stack

在Java中存在一个栈结构的实现类,这个类是Stack类;
Stack类是Vector类的子类,从集成的角度来说,Stack类是List接口的实现类,同样属于Collection接口的实现类之一;
从这个角度来说,Stack类同样具有List接口下其他实现类类似的功能,能够有序可重复的保存元素;
但是除了这些特性之外,Stack类还提供了一些额外的方法,能够从数据结构的角度体现出栈结构的特性。

2.1.3 案例

1、.数组逆序

import java.util.Arrays;
import java.util.Stack;

public class ArrayReverseByStack {
	
	/**
	 * 使用栈结构实现数组元素逆序
	 * @param array 参数数组
	 */
	public void reverse(int[] array) {
		
		//[1]创建一个栈结构,用来逆序数组中的元素
		Stack<Integer> reverseStack = new Stack<>();
		
		//[2]将数组中全部元素入栈
		for(int i = 0; i < array.length; i++) {
			reverseStack.push(array[i]);
		}
		
		//[3]将栈结构中的所有元素出栈,出栈过程就是讲数组中元素逆序的过程
		for(int i = 0; i < array.length; i++) {
			array[i] = reverseStack.pop();
		}
		
	}
	
	public static void main(String[] args) {
		
		int[] array = new int[] {1,3,5,7,9};
		
		ArrayReverseByStack arbs = new ArrayReverseByStack();
		arbs.reverse(array);
		
		System.out.println(Arrays.toString(array));
		
	}
	
}

2、.10进制正整数转2进制

import java.util.Stack;

public class DecimalToBinary {
	
	/**
	 * 将一个10进制正整数转换为一个2进制字符串并返回
	 * @param num 作为参数的10进制整数
	 * @return 10进制整数对应的2进制字符串
	 */
	public String toBinary(int num) {
		
		//[1]创建一个栈结构,用来存储整除法产生的余数
		Stack<Integer> binaryStack = new Stack<>();
		
		//[2]对参数num进行对2的整除法,直到这个数取值为0为止,将过程中产生的所有余数全部入栈(最后产生的0不用入栈)
		int remainder = 0;  //创建一个临时变量,用来保存num对2的余数
		while(num > 0) {
			remainder = num % 2;
			binaryStack.push(remainder);  //余数入栈
			num /= 2;  //别忘了对num除以2,因为上面的步骤只是取余,没有除以2的功能
		}
		
		//[3]将栈中所有余数出栈,出栈过程就是倒排余数的过程
		String result = "0B";
		while(!binaryStack.isEmpty()) {  //只要栈结构不是空,就继续元素出栈
			result += binaryStack.pop();
		}
	
		//[4]返回结果值
		return result;
		
	}

	public static void main(String[] args) {
		
		int num = 12;  //12的2进制结构:0b1100
		
		DecimalToBinary dtb = new DecimalToBinary();
		String result = dtb.toBinary(num);
		System.out.println(result);
		
	}
	
}

2.2 队列

2.2.1 队列的结构特性

  • 队列的结构特性是:元素先进先出(First In First Out,简称FIFO)
  • 队列结构的特征就和现实生活中的排队买东西一样,先来排队的先买,一切先来后到,元素按照进入队列的顺序出队列
  • 我们将元素键入队列的操作,称之为元素入队列
  • 将元素从队列中取出的操作,称之为元素出队列
  • 将元素出队列的一端称之为队头(front)
  • 将元素入队列的一端称之为队尾(rear)

2.2.2 Java中的队列结构:LinkedLIst

  • Collection接口下,不仅仅有List和Set两大子接口,实际上还存在着一个名为Queue的接口,这个接口从名字上来看,本身就是队列的含义,并且这个接口还有一个子接口名为Deque(双端队列)
  • LinkedList类,一方面实现了List接口,一方面也实现了Deque接口,所以我们可以认为LinkedList本身就是一个通过链表实现的双端队列结构
  • 双端队列是一种两端可以同时元素入队列、出队列的结构,也就是说,两端同为队头和队尾

同样的,在LinkedList类型中,也提供了一些方法,用来支持队列操作:

2.2.3 案例

1、利用两个栈实现一个队列

给定元素加入结构顺序:a b c d e
元素出结构顺序:a b c d e
这个结构功能等同于一个队列结构,但是内部要求使用两个栈结构实现

import java.util.Stack;

/**
 * 使用两个栈结构模拟的队列
 */
public class StackQueue<E> {
	
	private Stack<E> s1 = new Stack<>();
	private Stack<E> s2 = new Stack<>();
	
	/**
	 * 将元素加入这个结构的方法
	 * @param e 加入结构的元素
	 */
	public void add(E e) {
		
		//[1]如果栈s2中还有剩余元素,说明上一次的出栈并没有“出干净”,还需要将s2中的元素全部入栈s1当中,保证元素加入结构的相对顺序不变
		if(!s2.isEmpty()) {
			while(!s2.isEmpty()) {
				E tmp = s2.pop();  //s2出栈
				s1.push(tmp);  //s1入栈
			}
		}
		
		//[2]如果元素要加入这个结构的话,那么首先将这些元素全部加入栈s1当中
		s1.push(e);
		
	}
	
	/**
	 * 将元素从结构中退出的方法
	 * @return 退出结构的元素
	 */
	public E get() {
		
		//[1]如果元素要从结构中退出,那么将栈s1中所有的元素全部出栈,并按照元素出栈顺序加入到栈s2中
		if(!s1.isEmpty()) {
			while(!s1.isEmpty()) {
				E tmp = s1.pop();  //s1出栈
				s2.push(tmp);  //s2入栈
			}
		}
		
		//[2]将栈s2中的栈顶元素出栈并返回,这个过程就是元素按照加入结构顺序退出的过程
		if(!s2.isEmpty()) {
			return s2.pop();
		}
		return null;
		
	}
	
	public static void main(String[] args) {
		
		StackQueue<Character> sq = new StackQueue<>();
		
		//加入结构5个元素
		sq.add('A');
		sq.add('B');
		sq.add('C');
		sq.add('D');
		sq.add('E');
		
		//退出结构3个元素
		System.out.println(sq.get());
		System.out.println(sq.get());
		System.out.println(sq.get());
		
		//再次加入结构3个元素
		sq.add('F');
		sq.add('G');
		sq.add('H');
		
		//全部元素退出结构
		System.out.println(sq.get());
		System.out.println(sq.get());
		System.out.println(sq.get());
		System.out.println(sq.get());
		System.out.println(sq.get());
		
	}
	
}

2、用两个队列实现一个栈

给定元素加入结构顺序:a b c d e
元素出结构顺序:e d c b a
这个结构功能等同于一个栈结构,但是内部要求使用两个队列结构实现

步骤(1):将全部加入结构的元素加入队列q1
步骤(2):当元素e要退出结构的时候,将q1中除了元素e之外的其他元素全部出队列q1,并同时加入队列q2
步骤(3):将队列q1中的元素e出队列,此时队列q1空
步骤(4):当元素d要退出结构的时候,将q2中除了元素d之外的其他元素全部出队列q2,并同时加入队列q1
步骤(5):将队列q2中的元素d出队列,此时队列q2空
……
以此类推,就能够实现元素的倒序输出

import java.util.LinkedList;

/**
 * 使用两个队列结构模拟的栈
 */
public class QueueStack<E> {

	private LinkedList<E> l1 = new LinkedList<>();
	private LinkedList<E> l2 = new LinkedList<>();
	
	private LinkedList<E> currentList = l1;  //创建一个队列变量,用来记录当前应该向哪一个队列中添加元素,默认初始情况是向l1中添加元素
	
	/**
	 * 元素加入结构的方法
	 * @param e 加入结构的元素
	 */
	public void add(E e) {
		
		//[1]向currentList中添加元素
		currentList.offer(e);
		
	}
	
	/**
	 * 元素退出结构的方法
	 * @return 退出结构的元素
	 */
	public E get() {
		
		//[1]将当前用来存储元素的队列中的n个元素的前n-1个元素出队列,并存储到另一个空队列中
		if(currentList == l1 && !l1.isEmpty()) {
			while(l1.size() > 1) {
				E tmp = l1.poll();  //l1出队列
				l2.offer(tmp);  //l2入队列
			}
			
			//[2]现在队列l1中仅剩一个元素,将这个元素出队列并返回,并且后来的元素全部存储在l2中
			currentList = l2;
			return l1.poll();
			
		}else if(currentList == l2 && !l2.isEmpty()) {
			while(l2.size() > 1) {
				E tmp = l2.poll();  //l2出队列
				l1.offer(tmp);  //l1如队列
			}
			
			//[2]现在队列l2中仅剩一个元素,将这个元素出队列并返回,并且后来的元素全部存储在l1中
			currentList = l1;
			return l2.poll();
			
		}else {  //如果两个队列中都没有任何元素,那么直接返回空,方法结束
			return null;
		}
		
	}
	
	public static void main(String[] args) {
		
		QueueStack<Character> qs = new QueueStack<>();
		
		//相结构中添加5个元素
		qs.add('A');
		qs.add('B');
		qs.add('C');
		qs.add('D');
		qs.add('E');
		
		//退出结构3个元素
		System.out.println(qs.get());
		System.out.println(qs.get());
		System.out.println(qs.get());
		
		//再次追加3个元素
		qs.add('F');
		qs.add('G');
		qs.add('H');
		
		//全部元素出结构
		System.out.println(qs.get());
		System.out.println(qs.get());
		System.out.println(qs.get());
		System.out.println(qs.get());
		System.out.println(qs.get());
		
	}
	
}

 

 

posted @ 2019-06-14 00:27  傲骄鹿先生  阅读(108)  评论(0编辑  收藏  举报