数据结构(2)-- 栈、队列

【栈】

栈(stack)是一个特殊的线性表,只能在表尾(一端)进行插入和删除操作的线性表,先进后出(FILO)

栈的基本概念:

表尾称为栈顶,表头称为栈底。

插入元素到栈顶(表尾)的操作,称为入栈。从栈顶删除元素的操作,称为出栈

例子: 1.比如子弹压入弹夹,先放进的子弹会后打出来。后放进的先打出来。

2.生活中用的碗、盘子,摞在一块,后摞上去的,会先使用。

假设有3个元素a,b,c,入栈顺序是a,b,c,则它们的出栈顺序有几种可能?


【顺序栈】

利用一组地址连续的存储单元存放在栈底到到栈顶的数据元素。

附设一个指针(top)指向当前栈顶的位置

一、顺序栈的实现

  1. 顺序栈的结构表示

typedef struct
{
    int data[MAX];
    int top; //指向栈顶元素的指针
}seq_stack,*seq_t;

2.顺序栈的基本操作

creat_stack(); //创建顺序栈
full_stack(seq_t S); //判断S栈是否已满
empty_stack(seq_t S); //判断S栈是否为空
push_stack(seq_t S,int data); //入栈操作
pop_stack(seq_t S); //出栈操作
clean_stack(seq_t S); //清空栈
destory_stack(seq_t S); //销毁栈
print_stack(seq_t S); //打印栈中元素

main函数

int main(int argc, const char *argv[])
{
    seq_t S=creat_stack();   //seq_t是结构体指针类型
    push_stack(S,66);
    push_stack(S,77);
    push_stack(S,88);
    printf("压栈后数据:%d\n",S->top);
    pop_stack(S);
    printf("%d\n",S->top);
   print_stack(S);
   return 0;
}

2.1创建顺序栈

//创建顺序栈
seq_t creat_stack()
{
    seq_t p = (seq_t)malloc(sizeof(seq_stack));
    if(p==NULL)
    {
        printf("内存申请失败\n");
        return NULL;
    }
   printf("内存申请成功\n");
   p->top=-1; //最开始指向-1
   memset(p->data,0,sizeof(p->data));
   return p;
}

2.2判断顺序栈是否已满

//判满
int full_stack(seq_t S)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return -1;
    }
    return S->top==MAX-1?1:0;  //判断栈顶指针是否已经指向栈顶元素下标
}

2.3判断顺序栈是否为空

int empty_stack(seq_t S)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return -1;
    }
    return S->top==-1?1:0;  //指向-1则为空
}

2.4入栈

void push_stack(seq_t S,int data)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return;
    }
    if(!full_stack(S))  //栈不满,才可入栈
    {
        S->data[++(S->top)]=data;  //指针先上移,将数据放入 <=> S->top++; S->data[S->top]=data; 
   }
}

2.5出栈

void pop_stack(seq_t S)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return;
    }
    if(!empty_stack(S))  //栈不为空,则可出栈
    {
        printf("出栈元素为:%d\n",S->data[(S->top)--]); 
   }
}

2.6打印栈中数据

栈是从栈顶开始输出元素。因此遍历直接从栈顶指针所指向下标(s->top)打印即可

//打印
void print_stack(seq_t S)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return;
    }
    int i;
   for(i=S->top;i>=0;i--)   //栈是从栈顶开始输出元素。因此遍历直接从栈指针所指向下标打印即可
   {
       printf("%d\n",S->data[i]);
   }
    //S->top=S->top-1;
}

2.7清空栈

//清空栈
void clean_stack(seq_t S)
{
    if(S==NULL)
    {
        printf("入参为空\n");
        return;
    }
    if(empty_stack(S))
   {
       printf("栈为空\n");
       return;
   }
   S->top=-1;  //顺序栈因为用数组实现,清空栈直接指向-1就行
}

2.8销毁栈

//销毁栈
void destory_stack(seq_t *S)   
{
    if(S==NULL||*S==NULL)   //seq_t是一个结构体指针,因此对于S来说是一个二级指针,*S是解引用操作
    {                       
        printf("入参为空\n");
        return;
    }
    free(*S);
   *S=NULL;
}

上述 if(S==NULL || *S==NULL) 当中,S和*S位置不能互换。因为在对S解引用(*s)之前,要保证有二级指针才行。

这里用二级指针是因为main函数当中,P是一个指针,要对它销毁,要把它的地址传进销毁函数。(值传递和地址传递的区别


【链栈】

栈的链式存储结构简称为链栈.。链栈是通过单链表来实现的。

采用链式存储,便于结点的插入和删除操作。

每次入栈一个元素,向链表中加入一个结点(相当于头插法),出栈一个元素,删除一个结点

栈顶应该放在链首还是链尾合适?

因为栈具有“后进先出”的特点,所以每次在链表的尾部进行插入和删除,就要遍历整个链表来找到尾节点。

而在头部进行插入和删除时,只需根据头指针即可找到链表的首元素结点。不需要遍历链表。

所以链栈的出,入栈通过对链表进行头删头插来实现。

二、链栈的实现

1、结构的结构表示

typedef struct node
{
    int data;
    struct node* next;
}node,*node_t;

//头结点和单独定义拿出来
 typedef struct
 {
    int count;
    node_t top; //栈顶指针
}top_t;

2.链栈的基本操作:

create_links(); //创建链栈
create_node(int data); //创建结点
empty_links(top_t *P); //判空
push_links(top_t *P,int data); //入栈
pop_links(top_t *P); //出栈
print_link(top_t *P); //打印栈中元素
clean_links(top_t *P); //清空栈
destory_links(top_t **P); //销毁栈

main函数

int main(int argc, const char *argv[])
{
    top_t *P=create_links();
    push_links(P,66);
    push_links(P,77);
    push_links(P,88);
    pop_links(P);
    print_link(P);
    return 0;
}

2.1创建链栈

//创建链栈,创建一个栈顶指针
top_t *create_links()
{
    top_t * P=(top_t *)malloc(sizeof(top_t));
    if(P==NULL)
    {
        return NULL;
    }
    P->count=0;
   P->top=NULL;
   return P;
}

2.2创建结点

node_t create_node(int data)
{
    node_t n=(node_t)malloc(sizeof(node));
    if(n==NULL)
    {
        return NULL;
    }
    n->data=data; //赋予新结点数据
    return n;
}

2.3判空

//判空
int empty_links(top_t *P)
{
    if(P==NULL)
    {
        printf("入参为空\n");
        return -1;
    }
    return P->top==NULL?1:0; //头结点是否指向空
}

2.4入栈

void push_links(top_t *P,int data)
{
    if(P==NULL)
    {
        printf("入参为空\n");
        return ;
    }
    node_t new=create_node(data); //创建新结点
    new->next=P->top;  //头插
   P->top=new;
   P->count++;
}

2.5出栈

//头删,弹栈
void pop_links(top_t *P)
{
    if(P==NULL)
    {
        printf("入参为空\n");
        return;
    }
    node_t dele = P->top;  //dele指向第一个结点 
   if(!empty_links(P)) //保证栈中有元素
   {
       P->top=dele->next;  //头结点指向第一个结点的后继结点
       free(dele); //删除第一个结点
   }
   P->count--;
}

2.6打印链栈中数据

//打印
void print_link(top_t *P)
{
    if(P==NULL)
    {
        printf("入参为空\n");
        return ;
    }
    if(empty_links(P))
    {
        printf("栈为空\n");
        return;
    }
    node_t p=P->top; //从哪个结点开始打印
    while(p!=NULL)
    {
        printf("%d\n",p->data);
        p=p->next;
    }
}

2.7清空(只留头结点)

void clean_links(top_t *P)
{
    if(P==NULL)
    {
        printf("入参为空\n");
        return;
    }
    if(empty_links(P))
    {
        printf("栈为空\n");
        return;
    }
    node_t dele=P->top; //第一个结点
    node_t q; //辅助变量
    while(dele!=NULL)
    {
        //q保存要删除结点的下一个结点
        q=dele->next; 
        free(dele);
        //让dele往后走一位
        dele=q; 
    }
    P->count=0;
}

2.8销毁

//销毁
void destory_links(top_t **P)
{
    if(P==NULL)
    {
        printf("入参为空\n");
        return;
    }
    if(empty_links(*P))
   {
       printf("栈为空\n");
       return;
    }
    clean_links(*P);
    free(*P);
    *P=NULL;
}

【队列】

【链式队列】

一、链队的实现

1.链式队列的结构表示

//链队的结点类型
typedef struct node
{
    int data;
    struct node *next; //结点的指针域
}node,*node_t;

//指向链队头和尾的指针
typedef struct
{
    node_t front; //头指针
    node_t rear; //尾指针
}link_que,*que;

2.链式队列的基本操作

node_t create_linkque(); //创建链表 
que create_que(node_t H);  //创建队头指针和队尾指针
node_t create_node(int data);  //创建结点
int empty_linkque(que Q,node_t H);  //判空
void push_linkque(que Q,int data,node_t H);  //入队
void pop_linkque(que Q,node_t H);  //出队
void print_linkque(que Q,node_t H);  //打印
void clean_linkeque(que Q,node_t H);  //清空
void deatory_que(que *Q,node_t *H);  //销毁

main函数

int main(int argc, const char *argv[])
{
    node_t H=create_linkque();
    que Q=create_que(H);
    push_linkque(Q,23,H);
    push_linkque(Q,24,H);
    pop_linkque(Q,H);
    print_linkque(Q,H);
    deatory_que(&Q,&H);
    print_linkque(Q,H);
    return 0;
}

2.1 创建链表(即链队)

//创建链表
node_t create_linkque()
{
    node_t H=(node_t)malloc(sizeof(node));
    if(H==NULL)
    {
        printf("内存申请失败\n");
        return NULL;
    }
    H->data=-1;
    H->next=NULL;
    return H;
}

2.2 创建队头指针和队尾指针

//创建队头指针和队尾指针
que create_que(node_t H)
{
    que Q=(que)malloc(sizeof(link_que));
    if(Q==NULL)
    {
        printf("内存申请失败\n");
        return NULL;
    }
   Q->front=H;
   Q->rear=H;
   return Q;
}

2.3 创建结点

node_t create_node(int data)
{
    node_t p=(node_t)malloc(sizeof(node));
    if(p==NULL)
    {
        printf("内存申请失败\n");
        return NULL;
    }
    p->data=data;
   p->next=NULL;
   return p;
}

2.4 判空

int empty_linkque(que Q,node_t H)
{
    if(Q==NULL)
    {
        printf("入参为空\n");
        return -1;
    }
    return Q->front==Q->rear&&Q->rear==H?1:0;
}

2.5 入队(尾插)

void push_linkque(que Q,int data,node_t H)
{
    if(Q==NULL)
    {
        printf("入参为空\n");
        return;
    }
    node_t p=create_node(data);
    //当链队为空的情况
    if(empty_linkque(Q,H))
    {
        //Q->fornt=H,因为链队为空的时候Q->front和Q->next都指向H
        Q->front->next=p;
        Q->front=p;
        Q->rear=p;
    }
    else
    {
        Q->rear->next=p;
        Q->rear=p;
    }
}

2.6 出队(头删)

void pop_linkque(que Q,node_t H)
{
    if(Q==NULL)
    {
        printf("入参为空\n");
        return;
    }
    if(empty_linkque(Q,H))
    {
        printf("链队为空\n");
        return;
   }
   if(Q->rear==Q->front&&Q->rear!=H)
   {
       //当链队中只有一个元素的时候
       printf("出队的元素为%d\n",Q->front->data);
       Q->front=H;
       Q->rear=H;
       free(H->next);
       H->next=NULL;
       return;
   }
   printf("出队的元素为%d\n",Q->front->data);
   //保存要删除的结点
   node_t dele =Q->front;
   //Q->front指向第二个结点
   Q->front=Q->front->next;
   //头结点重新指向,现在链队中的第一个结点
   H->next=Q->front;
   free(dele);
}

2.7 打印

void print_linkque(que Q,node_t H)
{
    if(Q==NULL)
    {
        printf("入参为空\n");
        return;
    }
    if(!empty_linkque(Q,H))
    {
       node_t p=Q->front;
       while(p!=NULL)
       {
           printf("%d\n",p->data);
           p=p->next;
       }
   }
}

2.8 清空

//清空
void clean_linkeque(que Q,node_t H)
{
    if(Q==NULL)
    {
        printf("入参为空\n");
        return;
    }
    while(!empty_linkque(Q,H))
   {
       pop_linkque(Q,H);
   }
}

2.9 销毁

void deatory_que(que *Q,node_t *H)
{
    if(Q==NULL||*Q==NULL||H==NULL||*H==NULL)
    {
        printf("error\n");
        return;
    }
    clean_linkeque(*Q,*H);
    free(*Q);
   free(*H);
   //实现实参内的Q和H置空
   *Q=NULL;
   *H=NULL;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值