文章目录
一.栈
1.定义
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端
称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
特点:喝多了吐(先进先出,后进后出)。
图:
补充:在我们写代码用到的栈(堆栈),也是这一种结构,并且这个栈具有动态属性,所以我们一般的局部变量或者函数的调用都发生在这里,而且栈的空间使用是先使用高地址再使用低地址,所以我们也称堆栈是向下生长的。
图:
说明:这几个区并不是内存!而是进程地址空间(操作系统)。
2.实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据(先进先出)的代价比较小。
说明:
链表的尾插的时间复杂度为:O(N)
顺序表尾插的时间复杂度为:O(1)
静态和动态
动态:
typedef int SLDateType;
struct Stack
{
SLDateType* arr;//通过指针变量管理开辟的空间
int size;//1.当前所存数据的个数。2.下一个数据的下标。3.栈顶
int capacity;//当前栈的容量,考虑是否进行扩容。
};
静态:
#define capacity 10
typedef int SLDateType;
struct Stack
{
SLDateType arr[capacity];//数组的大小
int size;//同上
};
3.函数
1.初始化栈
void StackInit(Stack* p)//修改栈的内容,需要传指针进行修改
{
p->size = 0;
p->arr = NULL;
SLDateType* tmp = NULL;
tmp = (SLDateType*)realloc(p->arr, 4 * sizeof(SLDateType));
//realloc只能对初始化的指针进行开辟空间,未初始化的会进行报错
if (tmp == NULL)//对返回值进行检查
{
perror("Stack:realloc fail");
exit(-1);
}
p->arr = tmp;
p->capacity = 4;
}
2.在栈顶压入元素
static void CheckCapacity(Stack *p)
{
if (p->size == p->capacity)//说明栈的空间已满
{
SLDateType* tmp = NULL;
tmp = (SLDateType*)realloc(p->arr, sizeof(SLDateType) * (p->capacity) * 2);
if (tmp == NULL)
{
perror("CheckCapacity:realloc fail");
exit(-1);
}
p->capacity *= 2;
p->arr = tmp;
}
}
void StackPushBack(Stack* p, SLDateType x)
{
assert(p);
CheckCapacity(p);//检查当前栈的容量
p->arr[p->size++] = x;
}
3.出栈
void StackPopBack(Stack* p)
{
assert(p->size > 0);//出栈的前提是:栈里面得有元素。
p->size--;
}
4.获取栈顶元素
SLDateType StackTop(Stack* p)
{
assert(p->size > 0);//获取元素,前提也是
return p->arr[p->size-1];
}
5.获取栈的元素个数
int StackSize(Stack* p)
{
assert(p->size > 0);
return p->size;
}
6.确认栈是否为空
int StackEmpty(Stack* p)
{
if (p->size == 0)
{
return 1;
}
return 0;
}
7.销毁栈
void StackDestory(Stack* p)
{
assert(p);
free(p->arr);
p->arr = NULL;
p->size = 0;
p->capacity = 0;
}
二.队列
1.定义
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。
特点:先进先出(吃多了拉)
入队列:进行插入操作的一端称为队尾
说明:FIFO(First In First Out)——入队列
出队列:进行删除操作的一端称为队头
2.实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
结构:
typedef int QLNDateType;
//节点
typedef struct QListNode
{
QLNDateType val;
struct QListNode* next;
}QListNode;
//对列的结构
typedef struct Queue
{
QListNode* Top;
QListNode* Tail;
}Queue;
3.函数
1.初始化对列
void QueueInit(Queue* q)
{
q->Tail = NULL;
q->Top = NULL;
//将头和尾都置为空
}
2.入对列
void QueuePushBack(Queue* q,QLNDateType x)
{
//创建并初始化结点
QListNode* NewNode = (QListNode*)malloc(sizeof(QListNode));
if (NewNode == NULL)
{
perror("malloc fail");
exit(-1);
}
NewNode->next = NULL;
NewNode->val = x;
//链表为空
if (q->Top == NULL)
{
q->Tail = NewNode;
q->Top = NewNode;
return;
}
//链表不为空
else
{
q->Tail->next = NewNode;
q->Tail = NewNode;
}
}
3.出队列
void QueuePopFront(Queue* q)
{
//对列不能为空!
assert(q->Top);
//头删
QListNode* next = q->Top->next;//保存下一个结点的位置
if (q->Top == q->Tail)
{
q->Tail = NULL;
}
free(q->Top);
q->Top = next;
}
4.获取队尾元素
QLNDateType QueueTail(Queue q)
{
//对列不能为空
assert(q.Top);
return q.Tail->val;
}
5.获取队首元素
QLNDateType QueueTop(Queue q)
{
//对列不能为空
assert(q.Top);
return q.Top->val;
}
6.获取有效元素个数
int QueueSize(Queue q)
{
QListNode* cur = q.Top;
int count = 0;
while (cur)
{
count++;
cur = cur->next;
}
return count;
}
7.检测队列是否为空
int QueueEmpty(Queue q)
{
return q.Top == NULL;
}
8.销毁对列
void QueueDestory(Queue* q)
{
//将对列的首结点保留下来即可完成对列的删除
QListNode* cur = q->Top;
q->Top = NULL;
q->Tail = NULL;
while (cur)
{
QListNode* next = cur->next;
free(cur);
cur = next;
}
}
7.打印对列
void QueuePrint(Queue q)
{
QListNode* cur = q.Top;
while (cur)
{
printf("%d->", cur->val);
cur = cur->next;
}
printf("NULL\n");
}