欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据结构——复习三

程序员文章站 2024-01-17 09:41:52
...

栈和队列
栈:仅在表尾进行插入或删除操作的线性表
栈顶:在栈顶操作,是表尾,通常用top表示
栈底:bottom,是表头
空栈:空表
通常栈底固定,栈顶移动,特点是:先进后出(FILO)或后进先出(LIFO)
数据结构——复习三
有顺序栈和链栈
//我们打比赛的时候一般都不会自己构建,都是用现成的,哈哈,只是要学习一下这种思想,思考方式
顺序栈
利用一组地址连续的存储单元依次自栈底到栈顶存放栈的数据元素。在数组上实现时,栈底位置可以设置在数组的任一个端点,而栈顶是随着插入和删除而变化的,可以用一个整形变量top存放栈顶的指针,数据入栈或出栈时使top分别加1或减1。
top=-1,栈空,此时出栈,则下溢
top=M-1,栈满,此时入栈,则上溢
top的初值是-1
链栈
用链式存储结构实现的栈称为链栈。通常链栈可用单链表表示,因此其结点结构与单链表的结构相同。通常我们也不设头结点。
//以前的代码,现在拿来总结一下

//顺序栈
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int MAXN=1000;
typedef struct as{
    int data[1000];
    int top;//栈顶元素的下标
}seqstack;
seqstack s;
void init()
{
    s.top=-1;
}
void push()//入栈
{
 int x;
 if(s.top==MAXN-1)
 printf("栈满\n");
 else
 {
 scanf("%d",&x);
 s.top++;
 s.data[s.top]=x;
 }
}
void pop()//出栈
{
 int y;
 if(s.top==-1)
 printf("栈空\n");
 else
 {
 y=s.data[s.top];
 s.top--;
 printf("%d\n",y);
 }
}
int main()
{
    int n,i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        push();
    }
    for(i=1;i<=n;i++)
    {
        pop();
    }
    return 0;
}
//链栈
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct as{
    int date;
    struct as *next;
}stacknode,*linkstack;
linkstack s;
void init()
{
  s=NULL;
}
void push()//入栈
{
    int x;
    scanf("%d",&x);
    linkstack p;
    p=(linkstack)malloc(sizeof(stacknode));
    p->date=x;
    p->next=s;//这里是栈与链表的差别
    s=p;
}
void pop()//出栈
{
 if(s==NULL)
 printf("栈空\n");
 else
 {
     printf("%d\n",s->date);
     s=s->next;
 }
}
int main()
{
    int n,i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        push();
    }
    for(i=1;i<=n;i++)
    {
        pop();
    }

    return 0;
}

两种方式的比较:
顺序栈需预先定义栈的长度,浪费空间,链栈长度可变但需增加结构性开销。
程序中用多个顺序栈时,为减少栈的溢出,提高空间利用率,通常用一个数组空间存放多个顺序栈。
双向栈
两个栈共享一个向量空间,栈底分别设在两端。
数据结构——复习三

在这里插入代码片

栈的应用:
1.数制转换
2.括号匹配
3.栈与递归过程
数据结构——复习三
数据结构——复习三
队列:队列是一种只允许在表的一端插入,在另一端删除的存取受限的线性表。
队尾rear:插入端,线性表的表尾。
队头front:删除端,线性表的表头。
空队列:队列没有任何元素。
数据结构——复习三
顺序和链式存储结构
队列的顺序存储结构
跟栈不同队列用数组存在一些问题,设数组维数为M,则:
当f=0,r=M时,再有元素入队发生溢出——真溢出
当f不等于0,r=M时,再有元素入队发生溢出——假溢出
解决方法:
循环队列:
入队:q[r]=x;r=(r+1)%M;
出队:x=q[f];f=(f+1)%M;
还有一个问题
空队列条件:Q.rear==Q.front

满队列条件:Q.rear==Q.front
我们要区分队空和队满,有三种方法:
1.少用一个存储空间
2.引入一个标志变量区别空和满
3.使用计数器
链队列:需要指示队头和队尾的两个指针。
数据结构——复习三

//用链表
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node{//头是空的头结点,尾是正好指向最后一个数
    int data;
    struct node *next;
}Node,*queueptr;
typedef struct
{
    queueptr front;
    queueptr rear;
}LinkQueue;
void init(LinkQueue &q)
{
 q.rear=q.front=(queueptr)malloc(sizeof(Node));
 q.front->next=NULL;
}
int ans=0;
void push(LinkQueue &q)
{
int x;
queueptr p;
  while(1)
  {
    scanf("%d",&x);
    if(x==0)
    break;
    ans++;
    p=(queueptr)malloc(sizeof(Node));
    p->data=x;
    q.rear->next=p;
    q.rear=p;
  }
}
void put(LinkQueue &q)
{
    queueptr p;
    if(q.front==q.rear)
    return;
    p=q.front->next;
    printf("%d ",p->data);
    q.front->next=p->next;//改变头指针的位置
    if(q.rear==p)
    {
     q.rear=q.front;
    }

}
int main()
{
     LinkQueue q;
     int i;
     init(q);
     push(q);
     for(i=1;i<=ans;i++)
     {
         put(q);
     }

    return 0;
}
//用顺序结构
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//顺序表存储队列(循环),要判断是否为满和空,一般有两种方法,头在第一个元素的下标,尾在最后一个元素的后一个元素的下标
const int maxnsize=100;
typedef struct
{
 int data[maxnsize];
 int front;
 int rear;
}sequeue;
void init(sequeue &q)
{
    q.front=q.rear=0;
}

void enqueue(sequeue &q,int x)
{
 if((q.rear+1)%maxnsize==q.front)
 {printf("队满\n");return;}
 q.data[q.rear]=x;
 q.rear=(q.rear+1)%maxnsize;
}
void dequeue(sequeue &q)
{
    if(q.rear==q.front)
    {
        printf("队空\n");
        return;
    }
    printf("%d ",q.data[q.front]);
    q.front=(q.front+1)%maxnsize;
}
int main()
{
    int x,i;
    int ans=0;
    sequeue q;
    init(q);
    while(1)
    {
        scanf("%d",&x);
        if(x==0)
       break;
        enqueue(q,x);
        ans++;
    }
    for(i=1;i<=ans;i++)
    {
        dequeue(q);
    }
    printf("\n");
    return 0;
}

顺序链表中还有一种判断队列空满的方法。

typedef struct
{
    ElemType Q[m];
    int rear,front;  //队尾和队头指针
    int tag;    //标记, 0为空,1为非空
} CycQueue;
CycQueue  QueueIn(CycQueue cq,ElemType x)//入队
{
    if(cq.tag==1&&cq.front==cq.rear)
    {
        printf("队满\n");
        exit(0);
    }
    else
    {
        cq.rear=(cq.rear+1)%m;
        cq.Q[cq.rear]=x;//入队一个数,一定不空
        if(cq.tag==0)//这句删掉也行
        cq.tag=1;
        //由空变不空标记
    }
    return cq;
}
CycQueue  QueueOut(CycQueue cq)//出队
{
    if (cq.tag==0)
    {
        printf("队空\n");
        exit(0);
    }
    else
    {
        cq.front=(cq.front+1)%m;
        if(cq.front==cq.rear)//出队的时候只会造成队空
            cq.tag=0;    //队列由不空变空
    }
    return cq;
}

队列链表也可以用带头结点的循环链表实现,只用一个尾指针。

typedef struct Lqueue
{
    ElemType data;
    struct Lqueue *next;
} Lqueue,*Queueptr;
void QueueIn(Queueptr rear, ElemType x)
{
    //入队列
    s=(Queueptr)malloc(sizeof(LQueue));
    s->data=x;
    s->next=rear->next;       //元素插入队尾//必须要这样,因为尾后面连了头结点
    rear->next=s;
    rear=s;         //求得新的队尾
}
ElemType QueueOut(Queueptr rear)
{
    //出队列
    if(rear->next==rear)
        printf("队列为空\n");
    else
    {
        p=rear->next;
        q=p->next;
        p->next=q->next;
        x=q->data;
        //删除队头元素
        if(q==rear) rear=p;
        free(q);
        return(x);
    }
}
相关标签: 复习用的