2. 栈与队列
2.1 栈与队列的区别
栈和队列都是重要的线性数据结构,在一个特定范围内存储单元中存储的数据。与线性表相比,插入和删除受到更多的约束和限定,是限定性的线性表结构。栈是先进后出,队列是先进先出。
有时在数据结构中还有按照大小排队或按照一定条件排队的数据队列,这时不一定按照先进先出的方法读取数据。
2.2 如何实现栈
分别使用链表和数组来实现栈。
1、使用数组实现:
public class myStack<E>{
private Object[] stack;//创建一个对象数组
private int size;//数组中存储的元素数量
public stack(){
stack = new Object[10];//初始化栈大小
}
//判断栈是否为空
public boolean isEmpty{
return size==0;
}
//返回栈顶元素
public E peek(){
if(stack.length==0){
return null;
}
return (E) stack[size-1];
}
//压栈方法
public E push(E item){
ensureCapacity(size+1);//检查数组容量
stack[size++]=item;//将一个元素放入对象数组中
return item;
}
//弹栈方法
public E pop(){
while(stack!=null){
E e = peek();
stack[size-1]=null;
size--;
return e;
}
}
//判断数组是否满,若已经满了,则扩充数组空间
public void ensureCapacity(int size){
int len = stack.length;//数组当前的大小
if(size==len){//当目前的数组容量满
int newLen = 10;//每次增加的数组空间大小
stack = Array.copyOf(stack.newLen);//在数组中增加空间
}
}
}
2、使用链表实现:
//创建一个节点类
Class Node{
Node<E> next= null;//指向后继的指针
E data;//元素
public Node(E data){
this.data = data;
}
}
public class stack<E>{
Node<E> top = null;
//判断链表是否为空
public boolean isEmptiy(){
if(top==null){
return false;
}
}
//压栈
public void push(E data){
Node<E> newNode = new Node<E>(data);//创建一个新节点
newNode.next = top;//在链表中添加一个新节点
top = newNode;
}
//弹栈
public E pop(Node top){
while(top!=null){
E data = top.data;
top = top,next;
return data;
}
}
//栈顶元素输出
public E peek(Node top){
while(top!=null){
return top.data;
}
}
}
2.3 如何使用O(1)的时间复杂度求栈中最小元素
如果当前入栈的元素比原来栈中的最小值还小,将该值压入保存最小元素的栈中;在出栈时,若当前出栈的元素刚好是当前栈中的最小值,保存最小值的栈顶元素也出栈,使得当前最小值变为其入栈之前的那个最小值。
public class MyStack{
Stack<Integer> s = new Stack<Integer>();
Stack<Integer> min = new Stack<Integer>();
public void push(int data){
if(s.isEmpty()){
s.push(data);
min.push(data);
}
while(!s.isEmpty()){
if(data<min.peek()){
min.push(data);
}
s.push(data);
}
public int pop(){
if(min.isEmpty()){
return null;
}
while(!min.isEmpty()){
int d = min.peek();
int c = s.peek();
if(d==c){
min.pop();
}
return c;
}
}
public int min(){
if(min.isEmpty()){
return Integer.MAX_VALUE;
}
else return min.peek();
}
}
2.4 如何实现队列
可以使用数组或链表实现:
1、使用链表:
Class Node{
Node next = null;
int data;
public void Node(){
this.data = data;
}
}
public class Queue{
Node head = new Node();
Node tail = new Node();
//判断队列是否为空
public void isEmpty(){
if(head==null&&tail==null){
return null;
}
}
//入队
public void put(){
Node newNode = new Node();
if(head==null&&tail==null){
tail = head = newNode;
tail.next = head.next = newNode.next;
}
else{
tail = newNode;
tail.next = newNode.next;
}
}
public Node pop(){
if(head==null&&tail==null){
return null;
}
else{
h = head.data;
head = head.next;
}
}
public int length(){
int length = 0;
//Node tmp = head;
if(head==null&&tail==null){
return null;
}
else{
while(head!=null){
length++;
head = head.next;
}
}
return length;
}
}
2、使用数组实现,增加对队列的同步:
public class Queue{
private ArrayList<Integer> list = new ArrayList<Integer>();
private int length = 0;
//入队
public synchronized void put(int a){
list.add(a);
length++;
}
//出队
public synchronized E pop(){
length--;
return list.removeFilrst();
}
//判断队列是否为空
public synchronized boolean isEmpty(){
return size==0;
}
//队列长度
public synchronized int size(){
return size;
}
}
2.5 如何用两个栈模拟队列操作
假设用栈A和栈B模拟队列Q,A为插入栈,B为弹出栈,实现队列Q;再假设A和B都是空,则栈A是入队列功能,栈B为出队列功能。如果需要入队列,直接将元素压入栈A,如果需要出栈,当栈B中不为空,则直接从栈B中弹出,当栈B为空,则先将元素从栈A中放入栈B,再从栈B中弹出。
public class Queue{
Stack<Integer> A = new Stack<Integer>();
Stack<Integer> B = new Stack<Integer>();
//判断队列是否为空
public synchronized boolean isEmpty(){
if(A.isEmpty()&&B.isEmpty()){
return false;
}
}
//入队列
public synchronized put(int data){
A.push(data);
}
//出队列
public synchronized pop(){
if(B.isEmpty()){
while(!A.isEmpty()){
B.push(A.pop());
}
}
else{
return B.pop();
}
}
2.6 栈和队列的应用
1、栈在括号匹配中的应用
2、栈在表达式求值中的应用
3、栈在递归中的应用
4、队列在层次遍历中的应用
5、队列在计算机系统中的应用
2.7 特数矩阵的压缩存储
1、数组定义:
数组是由 n个相同类型的数据元素构成的有限序列,每个数据元素称为一个数组元素,每个元素在n个线性关系中的序号称为该元素的下标,下标的取值范围称为数组的维界,数组与线性表的关系:数组是线性表的推广。 一维数组可视为一个线性表,二维数组可视为其元素也是定长线性表的一线性表,以此类推。数组一旦被定义,其维数和维界就不再改变。因此,除结构的初始化和销毁外,数组只会有存取元素 修改元素的操作。
2、数组存储结构
大多数计算机语言都提供了数组数据类型 ,逻辑意义上 数组 采用计算 语言中的数组数据类型进行存储, 数组的所有元素在内存中占用一段连续的存储空间。一维数组存储结构关系如下:
对于多维数组,有两种映射方法:按行优先和按列优先。以二维数组为例,按行优先存储的基本思想是 先行后列,先存储行号较小的元素,行号相等先存储列号较小的元素。二维数组的行下标与列下标范围为[0,h1]和[0,h2],存储结构如下:
3、矩阵的压缩存储
压缩存储:指为多个值相同的元素只分配 一个存储空间,对零元素不分配存储空间。其目的是为节省存储空间。
特殊矩阵:指具有许多相同矩阵元素或零元素,并且这些相同矩阵元素或零元素的分布有一定规律性的矩阵。常见的特殊矩阵有对称矩阵、上(下) 角矩阵、对角矩阵等。
特殊矩阵的压缩存储方法:找出特殊矩阵中值相同的矩阵元素的分布规律,把那些呈现规律分布的、值相同的多个矩阵元素压缩存储到一个存储空间中。
4、稀疏矩阵