1.栈
1.1定义
-
性质:FILO、LIFO
-
栈顶指针 top 记录栈顶元素的位置,栈空top = -1
-
弹栈:代表栈顶元素的栈顶指针向下移动一位,逻辑上完成一次出栈操作(类比于Vector删除)
-
一对 () 可以等价为一个完整事件,(()) 可以看作事件与事件的完全包含关系
-
() 问题是分治思想,可以采用递归实现
-
递归实现借助的结构是系统栈,栈可以处理具有完全包含关系的问题
-
栈和队列的应用
1.2顺序栈
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Stack {
int *data, size, top;
} Stack;
Stack *initStack(int n) {
Stack *s = (Stack *)malloc(sizeof(Stack));
s->data = (int *)malloc(sizeof(int) * n);
s->size = n;
s->top = -1;
return s;
}
//freeStack()置栈区s==NULL
void freeStack(Stack **saddr) { //saddr指向Stack*
if (!(*saddr)) return ;
free((*saddr)->data);
free(*saddr);
*saddr = NULL; //置NULL
return ;
}
int expand(Stack *s) {
int expsize = s->size;
int *temp;
while (expsize) {
temp = (int *)realloc(s->data, sizeof(int) * (s->size + expsize));
if (temp) break;
expsize >>= 1;
}
if (!temp) return 0;
s->data = temp;
s->size += expsize;
printf("expand successfully, new size is %d\n", s->size);
return 1;
}
int push(Stack *s, int val) {
if (!s) return 0;
if (s->top + 1 == s->size) {
if (!expand(s))
return 0;
}
s->data[++s->top] = val;
return 1;
}
//isEmpty()和pop()独立封装,配合调用
int isEmpty(Stack *s) {
return !(s && s->top != -1); // return s || s->top == -1; 互为逆反
}
int pop(Stack *s) {
return s->data[s->top--];
}
void showStack(Stack *s) {
//if (isEmpty(s)) return ; ---> !s/栈空不输出
if (!s) return ;
printf("Stack: [");
for (int i = 0; i <= s->top; i++) {
i && printf(",");
printf("%d", s->data[i]);
}
printf("]\n");
return ;
}
int main() {
srand(time(0));
Stack *s = initStack(2);
int cnt = 10;
while (cnt--) {
int val = rand() % 100;
int opt = rand() % 4;
switch (opt) {
case 0:
case 1:
case 2:
printf("push %d, res = %s\n", val, push(s, val) ? "SUC" : "ERR");
break;
case 3:
//配合调用
isEmpty(s) ? printf("pop nothing~\n") : printf("pop %d\n", pop(s));
break;
}
showStack(s);
}
freeStack(&s);
printf("s = %p\n", s);
return 0;
}
- 理解指针看到什么?去掉一个*
1.3链式栈
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Node {
int val;
struct Node *next;
} Node;
typedef struct Stack {
Node *head;
} Stack;
Node *initNode(int val) {
Node *n = (Node *)malloc(sizeof(Node));
//if (!n) return NULL;
n->val = val;
n->next = NULL;
return n;
}
void freeNode(Node *p) {
if (p) free(p);
return ;
}
Stack *initStack() {
Stack *s = (Stack *)malloc(sizeof(Stack));
s->head = NULL;
return s;
}
void freeStack(Stack *s) {
if (!s) return ;
Node *p = s->head, *k;
while (p) {
k = p;
p = p->next;
freeNode(k);
}
free(s);
return ;
}
// 对于链栈,插入使用头插法,head始终指向栈顶元素
int push(Stack *s, int val) {
if (!s) return 0;
Node *n = initNode(val);
//if (!n) return 0;
n->next = s->head; // 头插
s->head = n;
return 1;
}
int isEmpty(Stack *s) {
return !s || s->head == NULL;
}
int pop(Stack *s) {
Node *k = s->head;
int tmp = k->val;
s->head = k->next;
freeNode(k);
return tmp;
}
void showStack(Stack *s) {
if (!s) return ;
printf("Stack: [");
Node *p = s->head;
while (p) {
printf("%d->", p->val);
p = p->next;
}
printf("NULL]\n");
return ;
}
int main() {
srand(time(0));
Stack *s = initStack();
int cnt = 10;
while (cnt--) {
int val = rand() % 100;
int opt = rand() % 4;
switch (opt) {
case 0:
case 1:
case 2:
printf("push %d, res = %s\n", val, push(s, val) ? "SUC" : "ERR");
break;
case 3:
isEmpty(s) ? printf("pop nothings~\n") : printf("pop %d\n", pop(s));
break;
}
showStack(s);
}
freeStack(s);
return 0;
}
- 链栈使用头插法,栈顶指针 head 指向链表头节点,方便入栈、出栈
2.队列
2.1定义
-
head指向队首,tail指向队尾+1
-
循环队列实际容量
q->size - 1
,为了避免队满时,与队空条件q->head == q->tail
冲突 -
循环队列
取余运算%实现循环,解决普通队列假溢出问题 -
2个基本操作:push、pop
-
出队判空&入队判满
初始化q->head = q->tail = 0
队空q->head == q->tail
队满(q->tail + 1) % q->size == q->head
-
为什么tail指向队尾的后一个元素?
判断队空还是队满的问题导致的
head指向队首,tail指向队尾
初始:head = tail = -1(初始值为0有歧义,元素为0个还是1个?)
队空: h e a d = = t a i l head == tail head==tail
出队到只剩1个元素时, h e a d = = t a i l head==tail head==tail发生了歧义
2.2顺序队列(循环队列)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Queue {
int *data, size, head, tail;
} Queue;
Queue *initQueue(int n) {
Queue *q = (Queue *)malloc(sizeof(Queue));
q->data = (int *)malloc(sizeof(int) * n);
q->size = n; //实际容量n-1
q->head = q->tail = 0; //初始化-1无法判断队满
return q;
}
void freeQueue(Queue *q) {
if (!q) return ;
free(q->data);
free(q);
return ;
}
int expand(Queue *q) {
int expsize = q->size;
int *tmp;
while (expsize) {
tmp = (int *)malloc(sizeof(int) * (q->size + expsize));
if (tmp) break;
expsize >>= 1;
}
if (!tmp) return 0;
int i, j;
for (i=q->head, j=0; i!=q->tail; i=(i+1)%q->size, j++) {
tmp[j] = q->data[i];
}
free(q->data);
q->data = tmp;
q->head = 0, q->tail = j; //tail利用循环变量j赋值
q->size += expsize;
printf("expand successfully~, new size is %d\n", q->size);
return 1;
}
//head->队首 tail->队尾+1
int push(Queue *q, int val) {
if (!q) return 0;
if ((q->tail + 1) % q->size == q->head) { //队满
if (!expand(q))
return 0;
}
q->data[q->tail] = val;
q->tail = (q->tail + 1) % q->size;
return 1;
}
int isEmpty(Queue *q) {
return !q || q->head == q->tail; //队空
}
int pop(Queue *q) {
int tmp = q->data[q->head];
q->head = (q->head + 1) % q->size;
return tmp;
}
void showQueue(Queue *q) {
if (!q) return ;
printf("Queue: [");
for (int i = q->head; i != q->tail; i = (i + 1) % q->size) {
i != q->head && printf(",");
printf("%d", q->data[i]);
}
printf("]\n");
return ;
}
int main() {
srand(time(0));
Queue *q = initQueue(1); //容量0,队满
int cnt = 10;
while(cnt--) {
int val = rand() % 100;
int opt = rand() % 4;
switch(opt) {
case 0:
case 1:
case 2:
printf("push %d, res = %s\n", val, push(q, val) ? "SUC" : "ERR");
break;
case 3:
isEmpty(q) ? printf("pop nothings~\n") : printf("pop %d\n", pop(q));
break;
}
showQueue(q);
}
freeQueue(q);
return 0;
}
2.3链式队列
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Node {
int val;
struct Node *next;
} Node;
typedef struct Queue {
Node *head, *tail; //链队尾插头删,因为删除需要尾节点前一个节点的地址,tail无法满足
} Queue;
Node *initNode(int val) {
Node *n = (Node *)malloc(sizeof(Node));
n->val = val;
n->next = NULL;
return n;
}
void freeNode(Node *p) {
if (p) free(p);
return ;
}
Queue *initQueue() {
Queue *q = (Queue *)malloc(sizeof(Queue));
q->head = q->tail = NULL;
return q;
}
void freeQueue(Queue *q) {
if (!q) return ;
Node *p = q->head, *k;
while (p) {
k = p;
p = p->next;
freeNode(k);
}
free(q);
return ;
}
int push(Queue *q, int val) {
if (!q) return 0;
Node *n = initNode(val);
//空栈与否
if (q->tail) {
q->tail->next = n;
q->tail = n;
} else {
q->head = n;
q->tail = n;
}
return 1;
}
int isEmpty(Queue *q) {
return !(q && q->head);
}
int pop(Queue *q) {
Node *k = q->head;
int tmp = k->val;
q->head = k->next;
freeNode(k);
if (!q->head) q->tail = NULL; // freeNode后队空
return tmp;
}
void showQueue(Queue *q) {
if (!q) return ;
printf("Queue: [");
Node *p = q->head;
while (p) {
printf("%d->", p->val);
p = p->next;
}
printf("NULL]\n");
return ;
}
int main() {
srand(time(0));
Queue *q = initQueue();
int cnt = 10;
while (cnt--) {
int val = rand() % 100;
int opt = rand() % 4;
switch (opt) {
case 0:
case 1:
case 2:
printf("push %d, res = %s\n", val, push(q, val) ? "SUC" : "ERR");
break;
case 3:
isEmpty(q) ? printf("pop nothings~\n") : printf("pop %d\n", pop(q));
break;
}
showQueue(q);
putchar(10);
}
freeQueue(q);
return 0;
}