栈是一种只能在一段进行插入和删除的线性数据结构,通常使用线性表来实现。栈满足 **后进先出(LIFO/ last in first out)**的特性
由于栈不能像线性表一样随意进行插入删除,因此可以将栈视为一种功能受限的线性表。
栈的管理结点和线性表的管理结点相同:
顺序表实现栈:数据域(data)、栈的总容量(total)、栈的大小(len)
链表实现栈:栈顶结点(头结点)的指针(*head)、栈的大小(len)
【顺序栈也可以使用和顺序表一样的扩容方式】
#include
#include
#include
typedef struct Stack{
int *data;
int total;
int len;
} Stack;
Stack *initStack(int total){
Stack *s = (Stack *) malloc(sizeof(Stack));
s->data = (int *) malloc(sizeof(int) * total);
s->len = 0;
s->total = total;
return s;
}
void freeStack(Stack *s){
if(!s) return ;
free(s->data);
free(s);
return ;
}
void push(Stack *s, int val){
if(!s) return ;
if(s->len == s->total) return ;
s->data[s->len] = val; //相当于顺序表的尾插法
++ s->len;
return ;
}
int isEmpty(Stack *s){
return !s || s->len == 0;
}
int top(Stack *s){
return s->data[s->len - 1];
}
int pop(Stack *s){
int val = top(s);
-- s->len;
return val;
}
int main(){
Stack *s = initStack(5);
for(int i = 0; i < 5; i++){
push(s, i * 2); // 0 2 4 6 8
}
while(!isEmpty(s)){
printf("%d ", pop(s)); // 8 6 4 2 0
}
printf("\n");
return 0;
}
#include
#include
#include
typedef struct Node{
int val;
struct Node *next;
} Node;
Node *initNode(int val){
Node *node = (Node *) malloc (sizeof(Node));
node->val = val;
node->next = NULL;
return node;
}
void freeNode(Node *node){
if(!node) return ;
free(node);
}
typedef struct Stack{
struct Node *head;
int len;
} Stack;
Stack *initStack(){
Stack *s = (Stack *) malloc (sizeof(Stack));
s->head = NULL;
s->len = 0;
return s;
}
void freeStack(Stack *s){
if(!s) return ;
Node *p = s->head;
while(p){
Node *q = p;
p = p->next;
freeNode(q);
}
free(s);
}
void push(Stack *s, int val){
if(!s) return ;
Node *node = initNode(val);
node->next = s->head;
s->head = node;
++ s->len;
}
int top(Stack *s){
return s->head->val;
}
int pop(Stack *s){
int val = top(s);
Node *node = s->head;
s->head = s->head->next;
freeNode(node);
-- s->len;
return val;
}
int isEmpty(Stack *s){
return !s || !s->head;
}
int main(){
Stack *s = initStack();
for(int i = 0; i < 10; i++) push(s, i);
while(!isEmpty(s)) printf("%d ", pop(s));
printf("\n");
return 0;
}
只能在一段进行插入,另一端进行删除的先行数据结构,通常用线性表来实现。
队列满足 **先进先出(FIFO / first in first out)**的特性。与栈类似,队列也可以被看作是一种功能受限的线性表。
队列的管理结点:
顺序表实现的队列:数据域(data)、队首下标(head)、队尾下标(tail)、队列的总容量(total)
链表实现的队列:队首结点的指针(*head)、队尾结点的指针(*tail)、队列的长度(len)
一般来说队列只能查看队首元素,队尾入队首出
每次出栈头指针都会往后移一位,会造成栈顶空间浪费的情况
#include
#include
#include
typedef struct Queue{
int *data;
int head, tail, total;
} Queue;
Queue *initQueue(int total){
Queue *q = (Queue *) malloc (sizeof(Queue));
q->data = (int *) malloc(sizeof(int) * total);
q->head = 0;
q->tail = 0;
q->total = total;
return q;
}
void freeQueue(Queue *q){
if(!q) return ;
free(q->data);
free(q);
return ;
}
void push(Queue *q, int val){
if(!q) return ;
if(q->tail == q->total) return ;
q->data[q->tail] = val;
++ q->tail;
}
int front(Queue *q){
return q->data[q->head];
}
int pop(Queue *q){
int val = front(q);
++ q->head;
return val;
}
int isEmpty(Queue *q){
return !q || q->head == q->tail;
}
int main(){
Queue *q = initQueue(10);
for(int i = 0; i < 9; i++){
push(q, i);
}
while(!isEmpty(q)){
printf("%d ", pop(q));
}
printf("\n");
return 0;
}
当head或tail大于队列总长size时,head或tail会变为0,即 (head + 1) % total 或者 (tail + 1) % total
#include
#include
#include
typedef struct Queue{
int *data;
int head, tail, total;
} Queue;
Queue *initQueue(int total){
Queue *q = (Queue *) malloc (sizeof(Queue));
q->data = (int *) malloc(sizeof(int) * total);
q->head = 0;
q->tail = 0;
q->total = total;
return q;
}
void freeQueue(Queue *q){
if(!q) return ;
free(q->data);
free(q);
return ;
}
//循环队列,保证在n个容量大小的情况下能存放n-1个元素
void push(Queue *q, int val){
if(!q) return ;
if(q->head == (q->tail + 1) % q->total) return ;
q->data[q->tail] = val;
q->tail = (q->tail + 1) % q->total;
}
int front(Queue *q){
return q->data[q->head];
}
int pop(Queue *q){
int val = front(q);
q->head = (q->head + 1) % q->total;
return val;
}
int isEmpty(Queue *q){
return !q || q->head == q->tail;
}
int main(){
Queue *q = initQueue(10);
for(int i = 0; i < 4; i++){
push(q, i);
}
while(!isEmpty(q)){
printf("%d ", pop(q));
}
printf("\n");
for(int i = 10; i < 19; i++){
push(q, i);
}
while(!isEmpty(q)){
printf("%d ", pop(q));
}
printf("\n");
return 0;
}
int expand(Queue *q){
int exTotal = q->total;
int *temp;
while(exTotal){
//realloc重新分配空间成功后,指针q->data会被回收,不可以再使用
temp = (int *) realloc (q->data, sizeof(int) * (q->total + exTotal));
if(temp) break;
exTotal >>= 1;
}
if(!temp) return 0;
int i = q->head, j = q->head; //j是原来q->data的head,i是新的temp的q->data的head
while(j != q->tail){
temp[i] = temp[j]; //不能使用temp[i] = q->data[j]
i = (i + 1) % (q->total + exTotal);
j = (j + 1) % q->total;
}
q->tail = i;
q->data = temp;
q->total += exTotal;
return 1;
}
//循环队列,保证在n个容量大小的情况下能存放n-1个元素
void push(Queue *q, int val){
if(!q) return ;
if(q->head == (q->tail + 1) % q->total) {
if(!expand(q)) return ;
}
q->data[q->tail] = val;
q->tail = (q->tail + 1) % q->total;
}
#include
#include
#include
typedef struct Node{
int val;
struct Node *next;
} Node;
Node *initNode(int val){
Node *node = (Node *) malloc (sizeof(Node));
node->val = val;
node->next = NULL;
return node;
}
void freeNode(Node *node){
if(!node) return ;
free(node);
}
typedef struct Queue{
struct Node *head, *tail;
int len;
} Queue;
Queue *initQueue(){
Queue *q = (Queue *) malloc (sizeof(Queue));
q->head = NULL;
q->tail = NULL;
q->len = 0;
return q;
}
void freeQueue(Queue *q){
if(!q) return ;
Node *p = q->head;
while(p){
Node *temp = p;
p = p->next;
free(temp);
}
free(q);
}
//队尾插入
void push(Queue *q, int val){
if(!q) return ;
Node *node = initNode(val);
if(q->len == 0){ //对于链表的第一次插入也可以改成NIL(虚头结点)
q->head = node;
q->tail = node;
} else {
q->tail->next = node;
q->tail = q->tail->next;
}
++ q->len;
}
int front(Queue *q){
return q->head->val;
}
//队首弹出
int pop(Queue *q){
int val = front(q);
Node *node = q->head;
if(q->len == 1){
q->head = NULL;
q->tail = NULL;
} else {
q->head = q->head->next;
}
freeNode(node);
-- q->len;
return val;
}
int isEmpty(Queue *q){
return !q || (!q->head && !q->tail);
}
int main(){
Queue *q = initQueue();
for(int i = 0; i < 10; i++) push(q, i);
while(!isEmpty(q)) printf("%d ", pop(q));
printf("\n");
return 0;
}
双向队列可以使用 双向链表 实现,与单链表的区别仅有每个结点存放的指针有两个,分别为前驱结点的指针prev和后继结点的指针next
双向队列同时拥有:头插、尾插、头删、尾删四种增删操作
双向队列既可以当作栈使用又可以当作队列使用
要是对您有帮助,点个赞再走吧~ 欢迎评论区讨论~