栈和队列是两种特殊的线性表,他们的逻辑结构和线性表相同,只是其运算规则较线性表有更多的限制。本文介绍如何使用顺序栈、顺序队列和优先队列以及使用的规则和要领。
技术要点
数组实现顺序栈与队列的技术要点如下:
- 栈是一种数据结构,限制仅在表的一端进行插入和删除运算的线性表。其数据项的插入和删除(获取)都只能在成为栈顶的一端完成。因为最后插入的数据项就是最先要删除的数据项。当数据项中没有元素时称为空栈。栈为后进先出(Last In First Out)的线性表,简称LIFO表。
- 顺序栈:栈的顺序存储结构,它是运算受限的线性表。顺序栈的元素用向量存放。栈底的位置是固定不变的,可设置在向量两端的任意一个端点。栈顶位置是随着进栈和出栈操作而变化的,用一个整形变量top(栈顶指针)来表示。
- 当程序同时使用两个栈时,可以将两个栈的栈底设在向量空间的两端,让两个栈各自向中间延伸。当一个栈里的元素较多,超过向量空间的一半时,只要另一个栈的元素不多,那么前者就可以占用后者的部分存储空间。只有当整个向量空间被两个栈占满时,才会发生上溢。因此,两个栈共享一个长度为m的向量空间和两个栈分别占用两个长度为[m/2] 和[m/2]的向量空间比较,前者发生上溢的概率要比后者小得多。
- 队列是只允许在一端进行插入,而在另一端进行删除的运算受限的线性表。允许删除的一端称为队头,允许插入的一端称为队尾,当队列中没有元素时称为空队列。队列可称为先进先出(First In First Out)的线性表,简称FIFO表。
- 顺序队列:队列的顺序存储结构,实际是运算受限的线性表。和顺序表一样,顺序队列用一个向量空间来存放当前队列中的元素。由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示队头元素和队尾元素在向量空间中的位置,他们的初值在队列初始化时均应置为0。
实现步骤
- 新建一个类名为TextStackAndQueue.java。
- 代码如下表示:
package com.sunyueqing.s1;
class Stack { //实现顺序栈的类
long stackArray[]; //栈数组
int size;
int top;
public Stack(int size) { //构造方法初始化大小为size的栈
this.size = size;
this.stackArray = new long[size];
this.top = -1;
}
public long pop() { //出栈操作
return stackArray[top--];
}
public void push(long value) { //入栈操作
stackArray[++top] = value;
}
public boolean isEmpty() { //判断栈是否为空
return top == -1;
}
public boolean isFull() { //判断栈是否已满
return top == size - 1;
}
public long peek() { //取栈顶元素
return stackArray[top];
}
}
class Queue { //实现顺序队列的类
private long queueArray[]; //队列数组
private int front; //队列的前端下标
private int rear; //队列的尾端下标
private int size; //队列的大小
private int count; //队列中元素的个数
public Queue(int size) { //构造方法初始化大小为size的队列
this.queueArray = new long[size];
this.size = size;
this.front = 0;
this.rear = -1;
this.count = 0;
}
public void insert(long value) { //插入操作
if (rear == size - 1) //队列已满
rear = -1;
queueArray[++rear] = value;
count++;
}
public long remove() { //删除操作
long temp = queueArray[front++];
if (front == size)
front = 0;
count--;
return temp;
}
public long peakFront() { //返回队列的第一个元素
return queueArray[front];
}
public boolean isEmpty() { //判断是否为空
return count == 0;
}
public boolean isFull() { //判断是否已满
return count == size;
}
public int Count() { //返回队列中元素的个数
return count;
}
public void print() { //输出队列元素
for (int i = front; i < front + count; i++) {
System.out.print(queueArray[i] + "\t");
}
System.out.println();
}
}
class PriorityQueue { //实现优先队列的类
private int count; //队列中元素的个数
private long priorityArray[]; //队列数组
private int size; //队列的大小
public PriorityQueue(int size) { //构造方法初始化大小为size的队列
this.size = size;
this.priorityArray = new long[size];
this.count = 0;
}
public void insert(long value) { //插入操作
int i;
if (count == 0)
priorityArray[count++] = value;
else {
for (i = count - 1; i >= 0; i--) { //循环找到比插入值大的位置
if (value < priorityArray[i]) {
priorityArray[i + 1] = priorityArray[i]; //依次移动位置
} else
break;
}
priorityArray[i + 1] = value; //插入值放到指定位置
count++;
}
}
public long remove() { //删除操作
return priorityArray[--count];
}
public boolean isEmpty() { //判断是否为空
return count == 0;
}
public boolean isFull() { //判断是否已满
return count == size;
}
public void print() { //输出队列元素
for (int i = 0; i < count; i++) {
System.out.print(priorityArray[i] + "\t");
}
System.out.println();
}
}
public class TextStackAndQueue { //操作顺序栈与队列的类
public static void main(String[] args) { //java程序主入口处
System.out.println("1.数组实现顺序栈");
Stack stack = new Stack(6); //实例化顺序栈,栈的大小为6
while (!stack.isFull()) { //只要栈不满就循环
long r = (long) (Math.random() * 20);
stack.push(r); //入栈
System.out.print(r + "\t");
}
System.out.println();
while (!stack.isEmpty()) { //只要栈不空就循环
long value = stack.pop(); //获得栈顶元素
System.out.print(value + "\t");
}
System.out.println();
System.out.println("--------------------------------------------");
System.out.println("2.数组实习顺序队列");
Queue queue = new Queue(6); //实例化顺序队列,队列的大小为6
while (!queue.isFull()) { //只要队列不满就循环
long value = (long) (Math.random() * 20);
queue.insert(value); //元素插入队列
}
queue.print(); //输出队列元素
while (!queue.isEmpty()) { //只要栈不空就循环
queue.remove(); //元素移除
queue.print(); //输出队列元素
}
queue.print(); //输出队列元素
System.out.println(queue.isEmpty()); //队列是否为空?
System.out.println("--------------------------------------------");
System.out.println("3.数组实现优先队列");
PriorityQueue priority = new PriorityQueue(6); //实例化顺序队列,队列的大小为6
while (!priority.isFull()) { //只要队列不满就循环
long value = (long) (Math.random() * 20);
priority.insert(value); //元素插入队列
}
priority.print(); //输出队列元素
}
}
3.运行结果
源程序解释
- Stack类实现顺序栈,包括入栈、出栈、置栈空、判断栈是否为空以及判断栈是否已满和取栈内的元素。入栈的push()方法需要将栈顶top加1,需要注意的是,top=size-1表示栈满,当栈满时再做入栈运算产生空间溢出的现象,简称“上溢”。出栈的pop()方法需要将栈顶top减1,top<0表示空栈。当栈空时,做出栈运算产生溢出现象,简称“下溢”。当取栈内的元素时,由于栈是先进后出的,则取到的元素是最后放入的元素。
- Queue类实现顺序队列,包括入队、出队、置空队列、判断队列是否为空以及判断队列是否已满和取队列中的元素。入队的insert()方法将新元素插入到rear所指的位置,然后rear加1,需要注意的是,rear=size-1表示队列已满,当队列满时,做进栈运算产生空间溢出的现象,简称“真上溢”。当队列中实际的元素个数远远小于向量空间的规模时,也可以由于尾指针已超越向量空间的上界而不能做入队操作,该现象称为“假上溢”。出队的remove()方法删去front所指的元素,然后将front加1并返回被删除的元素。当count为空时,做出队运算产生溢出,称为“下溢”。“下溢”常用作程序控制转移的条件。当取队列的元素时,由于队列是先进先出的,则取到的元素是最先放入的元素。
- PriorityQueue类实现优化队列,对队列中的元素进行从小到大的排列。入队的insert()方法循环查找一个大于要插入元素的位置,当找到大于要插入的元素时就跳出,然后为要插入的元素留出位置,将要插入的元素保存到该位置。再根据队列元素是否为空和是否已满条件输出队列中已排序的元素,这样就实现了队列的优化操作。