栈
1.栈是什么?
栈是一种先入后出后入先出的数据结构,其原理可以理解成从羽毛球桶的一端依次取出羽毛球或放入羽毛球,而且你只能从这端取,参考下面这个动图:
存入数据时,数据的存放位置是这样的:
取出数据时,顺序是这样的:
大概能明白了栈的先入后出和后入先出了吧
2.栈的代码实现
(在stack.h中声明这些数据结构和函数)
1.首先可以使用宏定义要确定我们要存入数据的类型,使用宏定义的好处就是以后代码的易修改.
假设我们要存入的数据类型是int型的数据,那么如下定义:
typedef int Type;
2.然后声明栈的大小,这里大小以10为例:
#define STACK_SIZE 10
3.栈的结构体声明,在结构体中使用数组来储存我们的数据,数组大小就是我们定义的大小,这样在结构体中可以使用top变量来存储我们要取或者要储存的数组下标值,比如top=1时,我们能取出来的值就是data[1],在存入数据时就会存入到data[top+1]的位置上去,然后top自增1:
typedef struct Stack //栈的结构体声明
{
Type data[STACK_SIZE]; //数据域
int top; //栈顶元素下标
}stack;
4.声明栈的各个功能,最基本的有栈的初始化、入栈、出栈、获取栈顶元素、判断栈是否为空、判断栈是否满了:
/*栈的功能声明*/
//栈的初始化函数
stack* stack_init();
//数据入栈函数
void stack_push(stack* st,Type val);
//数据出栈函数
Type stack_pop(stack* st);
//获取栈顶元素
Type stack_top(stack* st);
//判断栈是否为空
bool stack_empty(stack* st);
//判断栈是否满了
bool stack_full(stack* st);
5.接下来就是去实现这些功能(在Stack.cpp中实现):
(在Stack.cpp中实现stack.h中的函数)
(1)栈的初始化:
使用assert()断言来判断temp分配内存的情况,如果分配失败就会报错.成功就继续执行代码
在初始化时将top的值赋值为-1,因为top值对应了我们要存或者取的数据的数组下标,在初始化时数组中是没有值的,如果将top值赋值为0的话,就对应了数组[0]的数据,这样是错误的!
stack* stack_init()
{
stack* temp = (stack *)malloc(sizeof(stack));
assert(temp);
temp->top = -1; //初始化栈顶元素下标,-1表示栈中没有元素
return temp;
}
(2)判断栈是否满了,如果我们要取或者要存入数据的下标已经到达了9或者更高,说明我们这里的栈已经满了,因为我们的空间一共只有10个:
bool stack_full(stack* st){
return st->top >= STACK_SIZE - 1; //在这里我们的STACK_SIZE定义值的是10
}
(3)入栈函数,向栈中存入数据:
void stack_push(stack* st, Type val)
{
assert(st); //判断栈是否存在
assert(!stack_full(st)); //判断栈是否满了
st->data[++st->top] = val; //从栈顶插入元素
}
(4)判断栈是否为空,只要top不为-1,说明栈中有数据,反之top为-1,说明栈还是空的:
bool stack_empty(stack* st)
{
return st->top != -1;
}
(5)数据出栈函数,取出一个数据后top要-1,下一次就是取这个数据的前一个数据了:
Type stack_pop(stack* st)
{
assert(st);
assert(stack_empty(st));
Type val = st->data[st->top]; //记录当前栈顶元素
st->top--; //栈顶元素下标-1.因为这个时候已经取出当前元素了,下一次就是应该取前面一个元素了
return val;
}
(6)取出栈的当前元素:
Type stack_top(stack* st)
{
assert(st);
assert(stack_empty(st));
return st->data[st->top];
}
3.测试栈的各个功能:
#include <stdio.h>
#include <assert.h>
#include "queue.h"
#define S "%d"
#define P "%d\t"
void stack_test()
{
stack* st1 = stack_init();
Type val;
printf("输入要存入的数据:");
do
{
scanf(S, &val);
stack_push(st1, val);
} while ('\n' != getchar());
printf(P, stack_pop(st1));
printf(P, stack_pop(st1));
putchar('\n');
printf(P, stack_top(st1));
putchar('\n');
printf(P, stack_pop(st1));
printf(P, stack_pop(st1));
}
int main(){
stack_test();
getchar();
return 0;
}
输入0 1 2 3 4 5 6 7 8 9测试结果,其中第二行的单7是获取的栈的当前数据:
队列
1.队列是什么
队列就是类似于排队一样,想象一下在地铁站排队时候,先到的人排在前面,就最先进入地铁,后来的人就排到后面,后进入地铁,所以队列就是先入先出,后入后出,入指的就是去排队,出指的就是进入地铁,先排先进,后排后进.实现队列一般使用链表结构.
在存入数据时,如下图这样,依次放在之前数据的后面:
在取数据时,则取的就是先放入的数据了,如下图:
2.队列的代码实现
(在queue.h中声明数据结构和函数)
1.先定义我们要存入的数据类型,比如这里假设要存入int型:
typedef int Type;
2.声明链表节点结构体,一个节点就带一个数据,使用链表来将这个队列串起来:
typedef struct node{
Type data; //数据域
node* next; //指针域
}Node;
3.队列链表的声明
typedef struct Queue{
Node* front; //队首指针
Node* back; //队尾指针
}Queue;
4.声明队列各种功能的函数:
//队列单链表的初始化
Queue* queue_init();
//队列单链表节点的初始化
Node* node_create(Type val);
//数据入队函数
void queue_push(Queue* q, Type val);
//数据出队函数
Type queue_pop(Queue* q);
//获取队首元素
Type queue_front(Queue* q);
//获取队尾元素
Type queue_back(Queue* q);
//判断队列是否为空
bool queue_empty(Queue* q);
(Queue.cpp中实现这些函数)
5.实现这些功能函数:
(1)队列单链表的初始化:
Queue* queue_init()
{
Queue * temp = (Queue *)malloc(sizeof(Queue));
assert(temp);
temp->front = temp->back = NULL; //队首和队尾指针初始化为空
return temp;
}
(2)给定数据,实现节点的初始化:
Node* node_create(Type val)
{
Node* temp = (Node *)malloc(sizeof(Node));
assert(temp);
temp->data = val; //节点数据域的初始化
temp->next = NULL; //节点指针域的初始化
return temp;
}
(3)数据入队函数:
void queue_push(Queue* q, Type val)
{
assert(q);
if (q->front == NULL)
{
q->front = node_create(val); //创建队列的第一个节点
q->back = q->front; //队列只有一个节点,其既是头部也是尾部
}
else
{
q->back->next = node_create(val);
q->back = q->back->next;
}
}
(4)数据出队函数:
Type queue_pop(Queue* q)
{
assert(q); //整个链表不存在
assert(q->front); //链表为空
Node *temp = q->front;
Type val = temp->data;
q->front = q->front->next;
free(temp);
temp = NULL;
return val;
}
(5)获取队首元素:
Type queue_front(Queue* q)
{
assert(q);
assert(q->front);
return q->front->data;
}
(6)获取队尾元素:
Type queue_back(Queue* q){
assert(q);
if (queue_empty(q))
return NULL;
return q->back->data;
}
(7)判断队列是否为空:
bool queue_empty(Queue* q)
{
assert(q); //整个链表不存在
return q->front == NULL;
}
3.测试队列的各个功能:
#include <stdio.h>
#include <assert.h>
#include "queue.h"
void queue_test(){
Queue* q1 = queue_init();
Type val;
printf("输入要存入的数据:");
do{
scanf(S, &val);
queue_push(q1,val);
} while ('\n' != getchar());
printf("获取队列的当前值:");
printf(P, queue_pop(q1));
printf("获取队列的当前值:");
printf(P, queue_pop(q1));
putchar('\n');
}
int main(){
queue_test();
getchar();
return 0;
}
存入数据1,2,3,4,5,6,运行结果如下: