1. 什么是栈,栈有什么特性?
栈(Stack)作为一种限定性线性表,是将线性表的插入和删除操作限制为仅在表的一端进行,通常将表中允许进行插入、删除操作的一端称为栈顶(Top),因此栈顶的当前位置是动态变化的,同时,表的另一端称为栈底(Bottom)。当栈中没有元素时称为空栈。
栈的插入操作可以形象的称为入栈或进栈。
栈的删除操作称为出栈或退栈。
总的来说:栈又称为后进先出(Last In First Out,LIFO)的线性表。
生活中有很多类似栈的例子,比如说:手枪子弹夹中的子弹。接下来我们用C语言实现一个动态栈。
2. 用C语言实现一个动态栈
typedef int SDataType;
typedef struct Stack
{
SDataType* _array;
int _capacity;
int _size; // 表示栈中有效元素的个数 代表栈顶位置
}Stack;
void StackInit(Stack* ps);
void StackInit(Stack* ps)
{
assert(ps);
ps->_array = (SDataType*)malloc(sizeof(SDataType) * 3);
if (NULL == ps->_array)
{
assert(0);
return;
}
ps->_capacity = 3;
ps->_size = 0;
}
void StackPush(Stack* ps, SDataType data);
void StackPush(Stack* ps, SDataType data)
{
// 检测是否有空间
CheckCapacity(ps);
ps->_array[ps->_size++] = data;
}
void CheckCapacity(Stack* ps)
{
assert(ps);
if (ps->_size == ps->_capacity)
{
// 开辟新空间
int newCapacity = ps->_capacity * 2;
SDataType* pTemp = (SDataType*)malloc(sizeof(SDataType)*newCapacity);
if (NULL == pTemp)
{
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;
}
}
void StackPop(Stack* ps);
void StackPop(Stack* ps)
{
assert(ps);
if (StackEmpty(ps))
return;
ps->_size -= 1;
}
SDataType StackTop(Stack* ps);
SDataType StackTop(Stack* ps)
{
assert(ps);
return ps->_array[ps->_size - 1];
}
int StackSize(Stack* ps);
int StackSize(Stack* ps)
{
assert(ps);
return ps->_size;
}
int StackEmpty(Stack* ps);
int StackEmpty(Stack* ps)
{
assert(ps);
return 0 == ps->_size;
}
void StackDestroy(Stack* ps);
void StackDestroy(Stack* ps)
{
assert(ps);
if (ps->_array)
{
free(ps->_array);
ps->_capacity = 0;
ps->_size = 0;
}
}
3. 栈和程序运行时的栈区有什么区别?
栈(数据结构):一种先进后出的数据结构。。它是一种概念,或者说是一种逻辑技术,与语言、平台无关。
栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。即遵循后进先出的管理方法。
好比数据结构中的栈是一项先进的技术,在内存管理中采用了该技术,在CPU的调度中可能也采用这种技术。
4. 为什么将递归程序转化成循环时需要用到栈?
在实现函数调用的时候,系统底层就是用栈来保存函数运行现场的;具体来说,每次调用函数时,会把当前函数的局部变量和返回地址都压栈保存起来,当函数调用结束返回的时候,再把局部变量从栈里弹出来。
而递归的核心就是重复的函数调用。因此如果要变成循环,就可能需要自己实现栈数据结构用来保存一些状态变量;这其实就是在模拟函数调用。
5.什么是队列,队列有什么特性?栈和队列有什么区别?
队列(Queue)是另一种限定性的线性表,它只允许在表的一端插入元素,而在另一端删除元素,所以队列具有先进先出(First In First Out,FIFO)的特性。
日常生活中的排队就是队列的一个例子。
在队列中,允许插入的一端称为队尾(Rear)。允许删除的一端称为队头(Front)。
栈和队列的区别:
1、队列先进先出,栈先进后出。
2、对插入和删除操作的"限定"不同。
栈是限定只能在表的一端进行插入和删除操作的线性表。
队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
3、遍历数据速度不同。
栈只能从头部取数据,也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性。
队列则不同,它基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影响数据结构,速度要快的多。
接下来用C语言实现一个队列。
6. 用C语言实现一个队列
typedef int QDataType;
typedef struct QNode
{
struct QNode* _pNext;
QDataType _data;
}QNode;
typedef struct Queue
{
QNode* _front; // 指向队头元素
QNode* _back; // 指向队尾元素
}Queue;
void QueueInit(Queue* q);
void QueueInit(Queue* q)
{
assert(q);
q->_front = q->_back = NULL;
}
void QueuePush(Queue* q, QDataType data);
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* pNewNode = BuyQueueNode(data);
if (QueueEmpty(q))
q->_front = q->_back = pNewNode;
else
{
q->_back->_pNext = pNewNode;
q->_back = pNewNode;
}
}
QNode* BuyQueueNode(QDataType data)
{
QNode* pNewNode = (QNode*)malloc(sizeof(QNode));
if (NULL == pNewNode)
{
assert(0);
return NULL;
}
pNewNode->_data = data;
pNewNode->_pNext = NULL;
return pNewNode;
}
void QueuePop(Queue* q);
void QueuePop(Queue* q)
{
QNode* pDelNode = NULL;
if (QueueEmpty(q))
return;
pDelNode = q->_front;
if (NULL == pDelNode->_pNext)
{
q->_front = q->_back = NULL;
}
else
{
q->_front = pDelNode->_pNext;
}
free(pDelNode);
}
QDataType QueueFront(Queue* q);
QDataType QueueFront(Queue* q)
{
assert(q);
return q->_front->_data;
}
QDataType QueueBack(Queue* q);
QDataType QueueBack(Queue* q)
{
assert(q);
return q->_back->_data;
}
int QueueSize(Queue* q);
int QueueSize(Queue* q)
{
int count = 0;
QNode* pCur = q->_front;
while (pCur)
{
count++;
pCur = pCur->_pNext;
}
return count;
}
int QueueEmpty(Queue* q);
int QueueEmpty(Queue* q)
{
assert(q);
return NULL == q->_front;
}
void QueueDestroy(Queue* q);
void QueueDestroy(Queue* q)
{
QNode* pCur = q->_front;
while (pCur)
{
q->_front = pCur->_pNext;
free(pCur);
pCur = q->_front;
}
q->_front = q->_back = NULL;
}