学过线性表以后,用过的处理一般是头插 、尾插、局部插入以及删除。那么如何将线性表改造成一个可以按照一定顺序插入、按照一定顺序删除的数据结构呢?有了这种按照顺序插入和删除我们可以应用于哪些实例呢?

线性表-栈-队列的关系?

线性表的插入与删除可以在头部、尾部以及线性表中间的某个结点。
那么我们规定仅仅在一端进行插入与删除操作的数据结构我们定义为​​​栈​​​。
规定在一端进行插入,另外一端进行删除的数据结构我们定义为​​​队列​​​。
由此我们在线性表的基础之上重新定义了两种数据结构。
由于线性表分为​​​顺序表​​​和​​链表​​​,由此栈也分为​​顺序栈​​​和​​链栈​​​,队列也分为​​顺序队​​​与​​链队​​。

栈和队列有哪些特点呢?
  • 对于
    栈是仅在一端进行插入和删除的线性表。插入和删除的那一端为栈顶,固定不动的那一端为栈底。
    插入和删除称为​​​入栈​​​和​​出栈​​​。
    最主要的特点是​​​先进后出​​。
  • 对于队列
    队列是在一端进行插入、另外一端进行删除的线性表。插入的那一端为队尾,删除的那一端为队头。
    插入和删除称为​​​入队​​​和​​出队​​​。
    最主要的特点是​​​先进先出​​。
栈与队列的应用实例。

可以利用栈的先进后出的特性来解决某些问题。

  • 栈可以适用于算术表达式的求值(前缀、中缀。后缀)、字符匹配(括号匹配)、
    逆序输出、

可以利用队列的先进先出的特性来解决某些问题。

  • 在具体的程序设计中,只要涉及到先进先出的设计,即采用了队列的思想。
    队列的一个典型应用就是求解——迷宫问题。

暂时就了解这么多,等以后有接触在补充。

栈的代码实现

顺序栈的出栈和入栈

顺序栈的初始化

    int maxSize;
int[] data;
int top;
随后在main函数赋值即可完成初始化。

进栈操作

//元素进栈  
public void push(int x){
if(top==maxSize-1){
return;
}
else{
data[++top]=x;//先移指针后进栈。
}

出栈操作

//元素出栈
public void pop(){
if(top==-1)
return;
else{
int x;
x=data[top--];//先出栈再移动指针
System.out.println(x);
}

顺序表的进栈和出栈操作比较简单些,一般能用顺序栈的尽量用顺序栈。顺序栈其实就是对数组处理,只是有一个​​top​​时刻定位着数组最后一个元素的下标。

链栈的出栈和入栈
  • 链栈的初始化(​​带头结点​​).
//链表结点的定义
public class Lnode{
int data;
Lnode next;
}
private Lnode head=new Lnode();
//初始化
public void init(){
head.next=null;
}
  • 进栈操作
public void push(int x){
Lnode p=new Lnode();
p.data=x;
p.next=head.next;
head.next=p;
}
//链栈无需考虑是否栈满
  • 出栈操作
public void pop(){
if(head.next==null)
return;
else{
Lnode p=new Lnode();
p=head.next;
int x=p.data;
System.out.println("出链栈的是:"+x);
head.next=p.next;
p=null;
}
  • 从无论是链栈和顺序栈的代码,均和线性表中的顺序表和链表相差无几。顺序栈是加了一个定位数组中最后一个元素的位置的top"指针"。链栈是头插入与头结点下的删除。

队列的代码实现

顺序队的出栈和入栈
  • 顺序队的初始化
      private int maxSize;
private int[] data;
private int front;
private int rear;
public void init(int maxSize,int front,int rear){
this.maxSize=maxSize;
this.front=front;
this.rear=rear;
this.data=new int[maxSize];
}
  • 入队操作
//入队操作
public void enQueue(int x){
if(rear==maxSize-1)
return;
else
data[rear++]=x;//先添加元素,再移动指针
}
  • 出队操作
//出队操作
public void deQueue(){
if(rear==front)
return;
else{
int x=data[front++];//先取元素,在移动指针
System.out.println("出队的是:"+x);
}
}

顺序队的入队和出队中的指针的位置略有不同。严蔚敏版的原话是:​​在非空队列中,队首指针(front)指向队列的头元素,而尾指针(rear)指向队列的尾元素的下一个位置。​​​而天勤高分笔记是和其相反的:​​队尾指针(rear)指向刚进队的元素的位置,队首指针(front)指向刚出队元素的位置​​​。而我在上面写的跟这两种均不一样,我的是:​​队首指针(front)指向队列的头元素,队尾指针(rear)指向队列的尾元素。​​我写的这个不能适用于循环队列中。

链队的出栈和入栈
  • 链队的初始化
  public class Lnode{
int data;
Lnode next;
Lnode front;
Lnode rear;
}
private Lnode lqu=new Lnode() ;
//初始化为空
public void init(){
lqu.front=lqu.rear=null;
}
  • 入队
//入队操作
public void enQueue(int x){
Lnode p=new Lnode();
p.data=x;
p.next=null;
if(lqu.front==null)//若对队列为空则,rear和front同时指向新结点
lqu.front=lqu.rear=p;
else{
lqu.rear.next=p;
lqu.rear=p;
}
}
  • 出队操作
//出队操作
public void deQueue(){
Lnode p=new Lnode();

if(lqu.rear==null)
return;
p=lqu.front;
int x=p.data;
if(lqu.front==lqu.rear)//需要判断是不是最后一个结点(队列不需要带头结点),
lqu.front=lqu.rear=null;
else
lqu.front=p.next;
System.out.println("出队的元素是:"+x);
p=null;

链队的操作比较麻烦些,但是比较灵活。在front和rear的指针参与下不需要设置​​头结点​​​了。也就是说队列​​没有头结点​​。但是需考虑这俩个指针,比如入队为空,两个指针同时指向新结点。仅剩一个结点时出队,则两个指针同时为空。

总结

  1. 栈和队列均是线性表改造而成,所有其操作基本与线性表的操作差不太多。
  2. 栈是先进后出,队列是先进先出。
  3. 写代码时尽量用顺序栈和顺序队。
  4. 链队的入队出队操作中,要注意的是最后一个结点的出队,和链队为空时的入队。