您的位置:首页 > 理论基础 > 数据结构算法

数据结构(7)--队列

2016-09-03 18:19 120 查看
对于Queue这个词大家熟悉么?我相信学习Android对于这个词熟悉的程度可谓是极深,毕竟Android内部很多的实现都是靠着队列.Handler、service内部实现也是.其实在我们生活当中,队列的作用就类似于说,我们去排队打饭(原谅我这个吃货),肯定是有人从前面打完饭走了,有人从后面排队进来…这样就是一个队列,那么大家都可以看出其中的特点了吧.

 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作。

队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列。

英文为:FIFO—>First In First Out,先进先出,后进后出

注意:队列也是有有着头结点(front)和队尾结点(rear)的.

队列的顺序存储:

在顺序存储里面,我们会经常发生”假溢出”现象.

front指向头元素,rear指向尾元素的下一个位置.因为顺序队列是限定个数,所以一旦前面的全部出去了,front后移,但是后面的插进来,会发现越界,但是实际上前面还有空位.这就是假溢出.

解决假溢出,就需要通过循环队列,循环队列的意思就是头尾相接,但是头尾相接又会出现一个循环有可能为空的问题,所以我们的解决方法是通过计数器的方法,来判定.

代码:

public class ListQueue {
static final int defaultSize = 10; //默认队列的长度
int front;  //队头
int rear;   //队尾
int count;  //统计元素个数的计数器
int maxSize; //队的最大长度
Object[] queue;  //队列

public ListQueue() {
init(defaultSize);
}

public ListQueue(int size) {
init(size);
}

public void init(int size) {
maxSize = size;
front = rear = 0;
count = 0;
queue = new Object[size];
}

public void append(Object obj) throws Exception {
// TODO Auto-generated method stub
if (count > 0 && front == rear) {
throw new Exception("队列已满!");
}
//添加到尾节点
queue[rear] = obj;
rear = (rear + 1) % maxSize;
count++;
}

//从头结点删除,并且作为一个循环了实用front
public Object delete() throws Exception {
// TODO Auto-generated method stub
if (isEmpty()) {
throw new Exception("队列为空!");
}
Object obj = queue[front];
front = (front + 1) % maxSize;
count--;
return obj;
}

public Object getFront() throws Exception {
// TODO Auto-generated method stub
if (!isEmpty()) {
return queue[front];
} else {
return null;
}
}

public boolean isEmpty() {
// TODO Auto-generated method stub
return count == 0;
}

/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ListQueue queue = new ListQueue();
queue.append("a");
queue.append("b");
queue.append("c");
queue.append("d");
queue.append("e");
queue.append("f");

queue.delete();
queue.delete();

while (!queue.isEmpty()) {
System.out.println(queue.delete());
}
}
}

链式队列:

链式队列其实就是特殊的单链表,只不过它只能尾进头出而已.说到链式队列,我们第一想到的就是结点的不同,我们要安排结点的构造.

结点类我就不写了:

测试类:(主要关注我们的front rear的变化就好了)

private QueueNode<T> front,rear;//声明两个结点
public LinkedQueue() {
this(null);
}
//初始化结点
public LinkedQueue(T element) {
if(element == null) {
front = new QueueNode<T>(null);
rear = front;
}else {
rear = new QueueNode<T>(element);
front = new QueueNode<T>(null,rear);
}
}
public int length(){
if(isEmpty()) return 0;
int k=1;
QueueNode<T> temp = front.getNext();
while(temp!=rear){
k++;
temp=temp.getNext();

}
return  k;

}

//获取第一个元素
public T getHead() {
if(isEmpty()) return null;
return front.getNext().getData();
}
//判断空
public boolean isEmpty() {
return front == rear;
}
//加入元素,从后面加入
public boolean add(T element) {
if(element == null) return false;
QueueNode<T> temp = front;
rear.setNext(new QueueNode<T>(element));
rear = rear.getNext();
return true;
}
//移除元素,前面走人,所以要对front进行修改
public T remove() {
if(isEmpty()) return null;
T element = front.getNext().getData();
if(length() == 1)
rear = front;
else{
front.setNext(front.getNext().getNext());
}
return element;
}
//目标转换成字符串,拼接
public String toString() {
if(isEmpty()) return "[ ]";
StringBuffer sb = new StringBuffer("[ ");
QueueNode<T> temp = front.getNext();
while(temp != rear) {
sb.append(temp+" ");
temp = temp.getNext();
}
sb.append(temp+" ");
sb.append("]");
return sb.toString();
}

public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedQueue<String> queue = new LinkedQueue<String>("A");
System.out.println("queue="+queue+"   queue.length="+queue.length());
queue.add("B");
System.out.println("queue="+queue+"   queue.length="+queue.length());
System.out.println("the removint element="+queue.remove());
System.out.println("queue="+queue+"   queue.length="+queue.length());
}


相信大家在查询的时候,会遇到一些类似与优先队列,其实优先队列的实现是差不多的,基本上就是我们逻辑上会多出一个优先级变量来设定优先级.

面试题:

设计含最小函数min()的栈,要求min、push、pop、的时间复杂度都是O(1)?

思路:

这里需要加一个辅助栈,用空间换取时间。辅助栈中,栈顶永远保存着当前栈中最小的数值。具体是这样的:原栈中,每次添加一个新元素时,就和辅助栈的栈顶元素相比较,如果新元素小,就把新元素的值放到辅助栈中,如果新元素大,就把辅助栈的栈顶元素再copy一遍放到辅助栈的栈顶;

重点方法:

minStack.peek()—>获取栈顶元素.

import java.util.Stack;

/**
* Created by smyhvae on 2015/9/9.
*/
public class MinStack {

private Stack<Integer> stack = new Stack<Integer>();
private Stack<Integer> minStack = new Stack<Integer>(); //辅助栈:栈顶永远保存stack中当前的最小的元素

public void push(int data) {
stack.push(data);  //直接往栈中添加数据

//在辅助栈中需要做判断
if (minStack.size() == 0 || data < minStack.peek()) {
minStack.push(data);
} else {
minStack.add(minStack.peek());   //【核心代码】peek方法返回的是栈顶的元素
}
}

public int pop() throws Exception {
if (stack.size() == 0) {
throw new Exception("栈中为空");
}

int data = stack.pop();
minStack.pop();  //核心代码
return data;
}

public int min() throws Exception {
if (minStack.size() == 0) {
throw new Exception("栈中空了");
}
return minStack.peek();
}

public static void main(String[] args) throws Exception {
MinStack stack = new MinStack();
stack.push(4);
stack.push(3);
stack.push(5);

System.out.println(stack.min());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 java