数据结构简记--3

本文详细介绍了栈、队列和数组的基础知识及其实现。栈是一种只能在一端进行插入和删除的线性表,分为顺序栈和链栈。队列是一种允许在表的一端插入,在另一端删除的线性表,包括顺序队列和链队列。此外,还提到了双端队列的概念,允许在两端进行入队和出队操作。文章提供了各种基本操作的C语言实现,包括初始化、入栈、出栈、读栈顶元素、判空等,并给出了实际应用示例。
摘要由CSDN通过智能技术生成

第 3 章 栈、队列和数组

3.1 栈

3.1.1 栈的定义

        栈是只允许在一端进行插入或删除操作的线性表。

        栈顶:线性表允许进行插入删除的那一端。

        栈底:固定的,不允许进行插入删除的另一端。

        空栈:不含任何元素的空表。

3.1.2 栈的基本操作

        InitStack(&S):初始化一个空栈S。

        StackEmpty(S):判断一个栈是否为空,如栈S为空则返回1,否则返回0。

        Push(&S,x):进栈,若栈S未满,则将x加入使之成为新栈顶。

        Pop(&S,&x):出栈,若栈S未空,则弹出栈顶元素,并用x返回。

        GetTop(S,&x):读栈顶元素,若栈S非空,则用x返回栈顶元素。

        DestroyStack(&S):销毁栈,并释放栈S占用的存储空间(“&”表示引用调用)。

 3.2 顺序栈

 3.2.1 顺序栈的实现

        采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时附设一个指针(top) 指示当前栈顶元素的位置。

        栈的顺序存储类型可描述为

#define MaxSize 50          //定义栈中元素的最大个数
typedef int ElemType;
typedef struct{
    ElemType data[MaxSize]; //存放栈中元素
    int top;                //栈顶指针
}SqStack;

 3.2.2 顺序栈的基本操作

 初始化

void InitStack(SqStack *S)
{
    S->top=-1;
}

 判栈空

int StackEmpty(SqStack S)
{
    if(S.top==-1)
        return 1;
    else
        return 0;
}

 进栈

int Push(SqStack *S,ElemType e)
{
    if(S->top==MaxSize-1) //栈满,报错
        return 0;
    S->data[++S->top]=e;  //指针先加1,再入栈
    return 1;
}

 出栈

int Pop(SqStack *S,ElemType *e)
{
    if(S->top==-1)  //栈空,报错
        return 0;
    *e=S->data[S->top--]; //先出栈,指针再减1
    return 1;
}

 读栈顶元素

int GetTop(SqStack *S,ElemType *e)
{
    if(S->top==-1)  //栈空,报错
        return 0;
    *e=S->data[S->top]; //e记录栈顶元素
    return 1;
}

 输出栈

void list(SqStack *S)
{
    int i;
    for(i=0;i<=S->top;i++)
        printf("%4d",S->data[i]);
    printf("\n");
}

 3.3 链栈

 3.3.1 链栈的定义

        采用链式存储的栈称为链栈。

        链栈存储类型可描述为

typedef int ElemType;
typedef struct LinkStack{
    ElemType data;
    struct LinkStack *next;
}linkstack;

 3.3.2 链栈上的基本操作

初始化操作

linkstack * InitStack(void)
{
    linkstack *S;
    S=(linkstack *)malloc(sizeof(linkstack));
    S->next=NULL;
    return S;
}

取栈顶元素操作

int GetTop(linkstack *S,ElemType *e)
{
    if(S->next==NULL)
        return 0;       //若栈空,返回0
    *e=S->next->data;
    return 1;
}

 入栈操作

int Push(linkstack *S,ElemType e)
{
    linkstack *p;
    p=(linkstack *)malloc(sizeof(linkstack));
    if(!p) return 0; //申请空间失败,返回0
    p->data=e;
    p->next=S->next;
    S->next=p;
    return 1;
}

 出栈操作

int Pop(linkstack *S,ElemType *e)
{
    linkstack *q;
    if(S->next==NULL)
        return 0;       //若栈空,返回0
    q=S->next;
    *e=q->data;
    S->next=q->next;
    free(q);
    return 1;
}

 判空操作

int EmptyStack(linkstack *S)
{
    if(S->next==NULL)
        return 1;
    else
        return 0;
}

 输出操作

void list(linkstack *S)
{
	linkstack *p;
	p=S->next;
	while(p!=NULL)
	{
		printf("%4d",p->data);
		p=p->next;
	}
	printf("\n");
}

 3.4 队列

 3.4.1 队列的定义

         队列简称队,也是一种操作受限的线性表,只允许在表的一端插入,而在表的另一端进行删除。向队列中插入元素称为入队或进队;删除元素称为出队或离队。

        队头:允许删除的一端,又称队首。

        队尾:允许插入的一端。

3.4.2 队列的基本操作

        InitQueue(Q):初始化操作,构造一个空队列Q。

        GetLen(Q):求长度操作,返回队列Q的元素个数,即队列的长度。

        GetFront(Q,e):取队头元素操作,通过e返回队列Q的队头元素值。

        EnQueue(Q,e):入队操作,将值为e的元素插入到队列中,使e称为新的队尾元素。

        OutQueue(Q,&e):出队操作,删除队列Q中的队头元素,同时将队头元素通过e带回。原队列中的第 2 个元素称为新的队头元素。

        EmptyQueue(Q):判空操作,判断队列Q是否为空,若队列为空,则返回1,否则返回0。

        List(Q):从队头到队尾依次输出队列Q中的所有元素。

3.5 顺序队列

3.5.1 顺序队列

         顺序队列是指分配一块连续的存储单元存放队列中的元素,并附设两个指针:队头指针front指向队头元素,队尾指针rear指向队尾元素的下一个位置。

         顺序队列类型可描述为

#define MaxSize 50              //定义队列中元素的最大个数
typedef int ElemType;
typedef struct
{
    ElemType data[MaxSize];    //存放队列元素
    int front;                //队头指针
    int rear;                 //队尾指针
}SqQueue;

 3.5.2 循环队列

        将顺序队列臆造为一个环状的空间,即把存储队列元素的表从逻辑上视为一个环,称为循环队列。循环队列的类型描述与顺序队列一致。

3.5.3 循环队列上的基本操作

 初始化

void InitQueue(SqQueue *Q)
{
    Q->rear=Q->front=0;       //初始化队首、队尾指针
}
int GetLen(SqQueue *Q)
{
    return (Q->rear-Q->front+MaxSize)%MaxSize;
}

 判空操作

int IsEmpty(SqQueue Q)
{
    if(Q.rear==Q.front)
        return 1;
    else
        return 0;
}

 获取队列长度

int GetLen(SqQueue *Q)
{
    return (Q->rear-Q->front+MaxSize)%MaxSize;
}

 入队操作

int EnQueue(SqQueue *Q,ElemType e)
{
    if((Q->rear+1)%MaxSize==Q->front)
        return 0;
    Q->data[Q->rear]=e;
    Q->rear=(Q->rear+1)%MaxSize;
    return 1;
}

 出队操作

int OutQueue(SqQueue *Q,ElemType *e)
{
    if(Q->rear==Q->front)
        return 0;
    *e=Q->data[Q->front];
    Q->front=(Q->front+1)%MaxSize;
    return 1;
}

输出操作

void list(SqQueue *Q)
{
    int i;
    i=Q->front;
    while(i!=Q->rear)
    {
        printf("%4d",Q->data[i]);
        i=(i+1)%MaxSize;
    }
    printf("\n");
}

在主函数中调用上述函数

int main()
{
    SqQueue q;
    int n;
    InitQueue(&q);
    n=IsEmpty(q);
    printf("%d\n",n);
    EnQueue(&q,1);
    EnQueue(&q,2);
    EnQueue(&q,3);
    EnQueue(&q,4);
    EnQueue(&q,5);
    list(&q);
    n=IsEmpty(q);
    printf("%d\n",n);
    n=GetLen(&q);
    printf("%d\n",n);
    OutQueue(&q,&n);
    list(&q);
    printf("%d\n",n);
    return 0;
}

 3.6 链队列

 3.6.1 链队列的定义

         队列的链式表示称为链队列,它实际上是一个同时带有队头指针和队尾指针的单链表。

        队列的链式存储类型可描述为

typedef int ElemType;
typedef struct LinkNode{
    ElemType data;
    struct LinkNode *next;
}LinkNode;
typedef struct{
    LinkNode *front;
    LinkNode *rear;
}LinkQueue;

 3.6.1 链队列上的基本操作

 初始化

void InitQueue(LinkQueue *Q)
{
    Q->front=Q->rear=(LinkNode *)malloc(sizeof(LinkNode)); //建立头结点
    Q->front->next=NULL;                                   //初始为空
}

 判空操作

int IsEmpty(LinkQueue *Q)
{
    if(Q->front==Q->rear)
        return 1;
    else
        return 0;
}

 求队列长度

int GetLen(LinkQueue *Q)
{
    int i;
    LinkNode *p;
    p=Q->front->next;
    i=0;
    while(p!=NULL)
    {
        i++;
        p=p->next;
    }
    return i;
}

 入队操作

void EnQueue(LinkQueue *Q,ElemType e)
{
    LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
    s->data=e;
    s->next=NULL;
    Q->rear->next=s;
    Q->rear=s;
}

 出队操作

int DeQueue(LinkQueue *Q,ElemType *e)
{
    LinkNode *p;
    if(Q->front==Q->rear)
        return 0;
    p=Q->front->next;
    *e=p->data;
    Q->front->next=p->next;
    if(Q->rear==p)
        Q->rear=Q->front;
    free(p);
    return 1;
}

 取队头元素操作

int GetFront(LinkQueue *Q,ElemType *e)
{
    if(Q->front==Q->rear)
        return 0;
    *e=Q->front->next->data;
    return 1;
}

 输出操作

void list(LinkQueue *Q)
{
    LinkNode *p;
    p=Q->front->next;
    while(p!=NULL)
    {
        printf("%4d",p->data);
        p=p->next;
    }
    printf("\n");
}

 3.7 双端队列

        双端队列是指允许两端都可以进行入队和出队操作的队列,其元素的逻辑结构仍是线性结构。将队列的两端分别称为前端和后端,两端都可以入队和出队。

        输入受限的双端队列:允许在其一端进行插入和删除,但在另一端只允许删除的双端队列称为输入受限的双端队列。

        输出受限的双端队列:允许在其一端进行插入和删除,但在另一端只允许插入的双端队列称为输出受限的双端队列。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值