功能受限的表结构
对表结构的功能加以限制,形成了特殊的表结构
栈:
只有一个出入口的表结构,先进后出,FILO
顺序栈:
存储元素内存的首地址
栈的容量
栈顶位置
运算:
创建、销毁、入栈、出栈、栈满、栈空、获取栈顶元素、数量
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
//顺序栈
typedef struct Arraystack
{
TYPE* ptr; //存储元素首地址
size_t cal; //栈的容量
size_t top;//栈顶位置
}Arraystack;
//创建
Arraystack* creat_array_stack(size_t cal)
{
Arraystack* stack = malloc(sizeof(Arraystack));
stack->ptr = malloc(sizeof(TYPE)*cal);
stack->cal=cal;
stack->top=0; //入栈的位置 空增栈
return stack;
}
//销毁
void destroy_array_stack(Arraystack* stack)
{
free(stack->ptr);
free(stack);
}
//栈空
bool empty_array_stack(Arraystack* stack)
{
return !stack->top;
}
//栈满
bool full_array_stack(Arraystack* stack)
{
return stack->top >= stack->cal;
}
//入栈
bool push_array_stack(Arraystack* stack,TYPE val)
{
if(full_array_stack(stack)) return false;
stack->ptr[stack->top++] = val;
return true;
}
//出栈
bool pop_array_satck(Arraystack* stack)
{
if(empty_array_stack(stack)) return false;
stack->top--;
return true;
}
//栈顶
bool top_array_stack(Arraystack* stack,TYPE *val)
{
if(empty_array_stack(stack)) return false;
*val=stack->ptr[stack->top-1];
return true;
}
//数量
size_t size_array_stack(Arraystack* stack)
{
return stack->top;
}
bool is_pop(int* a, int* b,int len)
{
int i=0,j=0;
Arraystack* stack=creat_array_stack(len);
while(i<len)
{
push_array_stack(stack,a[i]);
int top=-10;
while(top_array_stack(stack,&top) && top==b[j])
{
pop_array_satck(stack);
j++;
}
i++;
}
bool flag= empty_array_stack(stack);
destroy_array_stack(stack);
return flag;
}
int main(int argc,const char* argv[])
{
Arraystack* stack = creat_array_stack(10);
for(int i=0; i<10; i++)
{
push_array_stack(stack,i+10);
int top=-10;
top_array_stack(stack,&top) && printf("top=%d\n",top);
}
printf("---------------\n");
while(!empty_array_stack(stack))
{
int top=-10;
top_array_stack(stack,&top) && printf("top=%d\n",top);
pop_array_satck(stack);
}
int a[5]={1,2,3,4,5},b[5]={5,4,3,2,1};
if(is_pop(a,b,5))
{
printf("yes");
}
else
{
printf("no");
}
}
链式栈:
数据项:
栈顶
节点数量
运算:
创建、销毁、入栈、出栈、栈满、栈空、获取栈顶元素、数量
栈的应用:
1、函数的调用、栈内存
2、生产者和消费者模型(仓库使用栈实现)
3、表达式的解析(中缀表达式转后缀表达式)
栈常见的笔试题:
某序列为入栈顺序,判断哪些是正确的出栈顺序
1 2 3 4 5
1 2 3 4 5 yes
3 2 1 5 4 yes
3 1 2 4 5 no 注意:边入边出
编程题:实现一个函数,判断序列b是否是序列a的出栈顺序
bool is_pop(int* a,int* b,int len)
问题:两个顺序栈,如何安排他们的存储方向,能够空间利用最大化
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define TYPE int
//设计单链表的节点
typedef struct Node
{
TYPE data;//节点的数据域
struct Node* next;//节点的指针域
}Node;
//创建节点
Node* creat_node(TYPE data)
{
//分配存储节点的内存
Node* node=malloc(sizeof(Node));
node->data=data;
node->next=NULL;
return node;
}
typedef struct Liststack
{
Node* top;
size_t cnt;
}Liststack;
//创建
Liststack* creat_list_stack(void)
{
Liststack* stack = malloc(sizeof(Liststack));
stack->top=NULL;
stack->cnt=0;
return stack;
}
//入栈
void push_list_stack(Liststack* stack,TYPE val)
{
Node* node = creat_node(val);
node->next = stack->top;
stack->top = node;
stack->cnt++;
}
//栈顶
TYPE top_list_stack(Liststack* stack)
{
return stack->top->data;
}
//栈空
bool empty_list_stack(Liststack* stack)
{
return NULL == stack->top;
}
//出栈
void pop_list_stack(Liststack* stack)
{
Node* temp=stack->top;
stack->top=stack->top->next;
free(temp);
stack->cnt--;
}
//数量
size_t size_list_stack(Liststack* stack)
{
return stack->cnt;
}
//销毁
void destroy_list_stack(Liststack* stack)
{
while(!empty_list_stack(stack))
{
pop_list_stack(stack);
}
free(stack);
}
int main(int argc,const char* argv[])
{
Liststack* stack=creat_list_stack();
for(int i=0; i<10; i++)
{
push_list_stack(stack,rand()%100);
if(!empty_list_stack(stack))
{
printf("top:%d\n",top_list_stack(stack));
}
}
printf("------------------\n");
while(!empty_list_stack(stack))
{
printf("top:%d size=%d\n",top_list_stack(stack),size_list_stack(stack));
pop_list_stack(stack);
}
}
队列:
一个端口进数据,另一个端口出数据,先进先出表,FIFO
顺序队列:
数据项:
存储元素的内存首地址
对头位置
队尾位置
队列容量
运算:
创建、销毁、入队、出队、队满、队空、查看对头、队尾、数量
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
typedef struct ArrayQueue
{
TYPE* ptr;
size_t cal;
size_t head; //front对头
size_t tail; //rear队尾 接下来要入队的位置
}ArrayQueue;
//创建
ArrayQueue* creat_array_queue(size_t cal)
{
ArrayQueue* queue=malloc(sizeof(ArrayQueue));
queue->ptr=malloc(sizeof(TYPE)*(cal+1)); //解决对空堆满问题
queue->cal=cal+1;
queue->head=0;
queue->tail=0;
return queue;
}
//销毁
void destroy_array_queue(ArrayQueue* queue)
{
free(queue->ptr);
free(queue);
}
//队空
bool empty_array_queue(ArrayQueue* queue)
{
return queue->head==queue->tail;
}
//队满
bool full_array_queue(ArrayQueue* queue)
{
return (queue->tail+1)%queue->cal==queue->head;
}
//入队
bool push_array_queue(ArrayQueue* queue,TYPE val)
{
if(full_array_queue(queue)) return false;
queue->ptr[queue->tail]=val;
queue->tail=(queue->tail+1)%queue->cal;
return true;
}
//出队
bool pop_array_queue(ArrayQueue* queue)
{
if(empty_array_queue(queue)) return false;
queue->head=(queue->head+1)%queue->cal;
return true;
}
//队头
TYPE head_array_queue(ArrayQueue* queue)
{
return queue->ptr[queue->head];
}
//队尾
TYPE tail_array_queue(ArrayQueue* queue)
{
return queue->ptr[(queue->tail+queue->cal-1)%queue->cal];
}
//数量
size_t size_array_queue(ArrayQueue* queue)
{
return (queue->tail+queue->cal-queue->head)%queue->cal;
}
int main(int argc,const char* argv[])
{
ArrayQueue* queue=creat_array_queue(10);
for(int i=0; i<10; i++)
{
push_array_queue(queue,rand()%100);
printf("%d ",tail_array_queue(queue));
printf("num=%d\n",size_array_queue(queue));
}
printf("---------------\n");
while(!empty_array_queue(queue))
{
printf("%d ",head_array_queue(queue));
printf("num=%d\n",size_array_queue(queue));
pop_array_queue(queue);
}
}
注意问题1:
由一维数组组成,对头位置head+队尾位置tail表示,如果入队则tail+1,出队则head+1,为了让队列可以循环使用,我们把队列看作一个环,因此每次+1操作都对队列容量取余
tail=(tail+1)%cal
head=(head+1)%cal
注意问题2:
为了解决判断对空、队满条件相同的问题,额外多申请一个容量但不使用,此时:
判断对空条件:head == tail
判断队满条件:(tail+1)%cal==head
顺序队列元素数量:
(tail+cal-head)%cal
还可以多加一个数据项,表示队列中的元素数量,也可以解决该问题,还不需要多少申请一个容量,但是是非常规的解决方法,不常考
链式队列:
由若干个节点组成
数据项:
对头指针
队尾指针
节点数量
运算:
创建、销毁、入队、出队、队空、查看对头、队尾、数量
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define TYPE int
//设计单链表的节点
typedef struct Node
{
TYPE data;//节点的数据域
struct Node* next;//节点的指针域
}Node;
//创建节点
Node* creat_node(TYPE data)
{
//分配存储节点的内存
Node* node=malloc(sizeof(Node));
node->data=data;
node->next=NULL;
return node;
}
//链式队列
typedef struct ListQueue
{
Node* head;
Node* tail;
size_t cnt;
}ListQueue;
//创建
ListQueue* creat_list_queue(void)
{
ListQueue* queue=malloc(sizeof(ListQueue));
queue->head = NULL;
queue->tail = NULL;
queue->cnt=0;
return queue;
}
//队空
bool empty_list_queue(ListQueue* queue)
{
return 0 == queue->cnt;
}
//入队
void push_list_queue(ListQueue* queue,TYPE val)
{
Node* node=creat_node(val);
if(empty_list_queue(queue))
{
queue->head = node;
queue->tail = node;
}
else
{
queue->tail->next = node;
queue->tail = node;
}
queue->cnt++;
}
//出队
bool pop_list_queue(ListQueue* queue)
{
if(empty_list_queue(queue)) return false;
Node* temp = queue->head;
queue->head = temp->next;
free(temp);
queue->cnt--;
if(empty_list_queue(queue)) queue->tail=NULL;
return true;
}
//队头
TYPE head_list_queue(ListQueue* queue)
{
return queue->head->data;
}
//队尾
TYPE tail_list_queue(ListQueue* queue)
{
return queue->tail->data;
}
//数量
size_t size_list_queue(ListQueue* queue)
{
return queue->cnt;
}
//销毁
void destroy_list_queue(ListQueue* queue)
{
while(pop_list_queue(queue));
free(queue);
}
int main(int argc,const char* argv[])
{
ListQueue* queue = creat_list_queue();
for(int i=0; i<10; i++)
{
push_list_queue(queue,rand()%100);
printf("tail:%d size:%d\n",tail_list_queue(queue),size_list_queue(queue));
}
printf("----------------\n");
while(!empty_list_queue(queue))
{
printf("head:%d size:%d\n",head_list_queue(queue),size_list_queue(queue));
pop_list_queue(queue);
}
destroy_list_queue(queue);
queue=NULL;
}
队列应用:
1、消息队列
2、树的层序遍历
3、图的广度优先遍历
4、封装线程池、数据池