什么是栈,栈有什么特性?
栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作.进行数据插入和删除的一端称为栈顶,另一端称为栈底.栈中元素遵守后进先出的原则LIFO(Last in First Out).
压栈:栈的插入操作称为进栈/压栈/入栈,入数据在栈顶.
出栈:栈的删除操作叫做出栈,出数据也在栈顶.
栈和程序运行时的栈区有什么区别?
数据结构中的栈:栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。
内存分配中的栈:内存中的栈区处于相对较高的地址上,如果以地址的增长方向为上方的话,栈地址在内存中是向下增长的。栈区中分配局部变量空间。
C语言实现一个动态栈
Stack.h
typedef int SDataType;
//栈的结构
typedef struct Stack
{
SDataType* array;
int capacity;
int size; // 表示栈中有效元素的个数,还可表示栈顶位置
}Stack;
Stack.c
//栈的初始化
void StackInit(Stack* ps) {
assert(ps);
ps->array = (SDataType*)malloc(sizeof(SDataType) * 3);
if (ps->array == NULL) {
assert(0);
return;
}
ps->capacity = 3;
ps->size = 0;
}
//压栈
void StackPush(Stack* ps, SDataType data) {
//检测是否有空间
CheckCapacity(ps);
ps->array[ps->size++] = data;
}
//出栈
void StackPop(Stack* ps) {
assert(ps);
if (StackEmpty(ps)) {
return;
}
ps->size -= 1;
}
//获取栈顶元素
SDataType StackTop(Stack* ps) {
assert(ps);
return ps->array[ps->size - 1];
}
//获取栈内元素个数
int StackSize(Stack* ps) {
assert(ps);
return ps->size;
}
//判断栈是否为空
int StackEmpty(Stack* ps) {
assert(ps);
return ps->size == 0;
}
//栈的销毁
void StackDestroy(Stack* ps) {
assert(ps);
if (ps->array) {
free(ps->array);
ps->capacity = 0;
ps->size = 0;
}
}
//检测栈是否有空间,没有的话动态开辟新空间
void CheckCapacity(Stack* ps) {
assert(ps);
if (ps->size == ps->capacity) {
//开辟新空间
int newCapacity = ps->capacity * 2;
SDataType* pTemp = (SDataType*)malloc(sizeof(SDataType)*newCapacity);
if (pTemp == NULL) {
assert(0);
return;
}
//拷贝元素
for (int i = 0; i < ps->size; ++i) {
pTemp[i] = ps->array[i];
}
//释放旧空间
free(ps->array);
ps->array = pTemp;
ps->capacity = newCapacity;
}
}
为什么将递归程序转化成循环时需要用到栈?
程序中的递归操作其实是每次调用自己进入新的状态,直到最后一次的状态能够满足递归的结束条件,然后返回到上次的状态。而栈有着后进先出的特性,那这样就可以理解递归每调用一层就压入栈,直到最后满足递归结束条件,再一层层弹出栈,那么用栈来将递归改为循环,就可以理解了。
什么是队列,队列有什么特性?栈和队列有什么区别?
队列是一种只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表.
队列具有先进先出FIFO(First In First Out)的特性.
入队列:进行插入操作的一端称为队尾.
出队列:进行删除操作的一端称为队头.
栈先进后出而队列是先进先出;栈是限定只能在表的一端进行插入和删除操作的线性表,而队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表;遍历数据速度不同.栈只能从头部取数据,也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性。队列则不同,它基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影响数据结构,速度要快的多.
C语言实现一个队列
Queue.h
typedef int QDataType;
//节点的结构
typedef struct QNode {
struct QNode* pNext;
QDataType data;
}QNode;
//队列的结构
typedef struct Queue {
QNode* front;//队头
QNode* rear;//队尾
}Queue;
Queue.c
//队列的初始化
void QueueInit(Queue* q) {
assert(q);
q->front = NULL;
q->rear = NULL;
}
//入队列
void QueuePush(Queue* q, QDataType data) {
assert(q);
QNode* pNewNode = BuyQueueNode(data);
if (QueueEmpty(q)) {
q->front = pNewNode;
q->rear = pNewNode;
}
else {
q->rear->pNext = pNewNode;
q->rear = pNewNode;
}
}
//出队列
void QueuePop(Queue* q) {
assert(q);
if (QueueEmpty(q)) {
return;
}
QNode* pDelNode = q->front;
if (pDelNode->pNext == NULL) {
q->front = q->rear = NULL;
}
else {
q->front = pDelNode->pNext;
}
free(pDelNode);
}
//获取队头元素
QDataType QueueFront(Queue* q) {
assert(q);
return q->front->data;
}
//获取队尾元素
QDataType QueueRear(Queue* q) {
assert(q);
return q->rear->data;
}
//获取队列元素个数
int QueueSize(Queue* q) {
assert(q);
int count = 0;
QNode* pCur = q->front;
while (pCur) {
count++;
pCur = pCur->pNext;
}
return count;
}
//判断队列是否为空
int QueueEmpty(Queue* q) {
assert(q);
return q->front == NULL;
}
//销毁队列
void QueueDestroy(Queue* q) {
QNode* pCur = q->front;
while (pCur) {
q->front = pCur->pNext;
free(pCur);
pCur = q->front;
}
q->front = q->rear = NULL;
}
//产生新节点
QNode* BuyQueueNode(QDataType data) {
QNode* pNewNode = (QNode*)malloc(sizeof(QNode));
if (pNewNode == NULL) {
assert(0);
return NULL;
}
pNewNode->data = data;
pNewNode->pNext = NULL;
return pNewNode;
}