一、栈
1、栈的概念与结构
栈是一种特殊的线性表,其只允许在固定的一段进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的元素遵循先入后出LIFO(Last In Frist Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出战,出数据也在栈顶。
2、栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构更优一些,因为栈只会在一侧进行数据的插入和删除,我们可以选择在数组的尾上插入和删除,这样的代价比较小,效率也更高一些。
接下来我们开始实现栈。
2.1、定义结构
首先我们需要一个数组,其次需要记录栈顶的位置,以及栈的容量。
typedef int STDataType;
typedef struct Stack
{
STDataType* data;
int top;//指向栈顶
int capacity;//栈的容量
};
2.2、初始化
在初始化时,top有两种初始化形式,第一种是top最开始为0,那么top之中指向的是栈顶元素的后一个位置。
栈为空时,top为0,
然后开始有元素入栈,每次入栈都会++。
top始终指向栈顶元素的后一个位置。
第二种是top最开始为-1,
栈为空时top为-1,
开始有元素入栈,
top始终指向栈顶元素。
代码如下
void STInitial(ST* pst)
{
assert(pst);
pst->data = NULL;
//top有两种初始化形式、
//1.最开始为0
pst->top = 0;
//2.最开始为-1
//pst->top=-1;
pst->capacity = 0;
}
2.3、入栈
入栈很简单,top指向的是栈顶元素的下一个位置,我们只需要把入栈的元素放到top指向的位置,再让top++即可。
入栈的一个重点在于当容量不够时,要扩容。
代码如下
void STPush(ST* pst,STDataType x)
{
assert(pst);
if (pst->top == pst->capacity)//如果空间不够了,那就扩容
{
//如果capacity为0,那就是第一次扩容,开始4个空间
//如果capacity不为0,那就每次开辟2倍的空间
int Newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
ST* tmp = (ST*)realloc(pst->data,Newcapacity * sizeof(STDataType));
assert(tmp);//如果开辟空间失败,程序就报错
pst->data = tmp;
pst->capacity = Newcapacity;
}
pst->data[pst->top] = x;
pst->top++;
}
2.4、出栈
在出栈时,栈不能为空,所以我们先写一个检测链表是否为空的函数,如果链表为空返回true,否则返回false。
代码如下
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;//top为0时栈空
}
接下里写出栈函数也是非常的简单,当链表为空时,直接报错,不为空,则让top--即可,没有必要真的把数据删除。
代码如下
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));//栈不能为空
pst->top--;
}
2.5、获取栈顶元素
top指向栈顶元素的后一个位置,top的前一个位置就是栈顶元素,注意,获取栈顶元素是栈也不能为空。
代码如下
STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));//栈不能为空
return pst->data[pst->top - 1];//返回栈顶元素
}
2.6、获取栈中有效元素的个数
有效元素的个数就是top。
代码如下
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
2.7、销毁栈
代码如下
STDestroy(ST* pst)
{
assert(pst);
free(pst->data);
pst->data = NULL;
pst->capacity = 0;
pst->top = 0;
}
二、队列
1、队列的概念与结构
队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(Frist In Frist Out)原则。
入队:进行插入操作的一端被称为队尾。
出队:进行删除操作的一端被称为队头。
2、队列的实现
队列的实现需要在一侧进行插入,另一侧进行删除,用数组效率较低,用链表更为合适。
2.1、定义结构
既然要使用链表,那么就要定义节点的结构
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueeuNode* next;
}QNode;
同时,为了提高效率,我们还要定义一个结构体,这个结构体包含了指向队头的队头指针、指向队尾的队尾指针,以及记录队列大小的size。
代码如下
typedef struct Queue
{
QNode* phead;//指向头结点
QNode* ptail;//指向尾结点
int size;//记录链表大小
}Queue;
逻辑图如下
2.2、初始化
代码如下
void QueueInitial(Queue* pq)
{
assert(pq);
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
2.3、判空
如果队列为空,则返回true,不为空返回false,判空的条件很简单,如果size==0,则为空,代码如下
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
2.4、入队
入队都是发生在队尾,入队时,需要考虑队是否为空,
当队列为空时,
直接让队头指针和队尾指针指向新节点即可。
当队列非空时,只需要让最后一个节点的next指向新节点,再让队尾指针指向新节点即可。
代码如下
void QueuePush(Queue* pq,QDataType x)
{
assert(pq);
//生成新节点
QNode* newnode = (QNode*)malloc(sizeof(Queue));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
//开始入队
if (QueueEmpty(pq))//如果队为空
{
assert(pq->phead==NULL);
pq->phead = pq->ptail = newnode;
}
else//如果队不为空
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;//每次入队
}
2.5、出队
出队是在队头发生的,出队时链表不能为空,
当链表有多个节点时,
定义一个指针headNext指向头结点的下一个节点,
把头结点释放掉,队头指针指向headNext指向的节点。
上面的思路对于队尾指针是没有任何处理室,但是当队列只有一个节点时,需要对队尾指针进行操作,
直接释放掉仅有的一个节点,然后把队头指针和队尾指针置空即可。
代码如下
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));//队列不能为空
if (pq->size==1)//队列只有1个节点
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else//队列有多个节点
{
Queue* headNext = pq->phead->next;//记录头结点的下一个位置
free(pq->phead);
pq->phead = headNext;
}
pq->size--;//每次出队size--
}
2.6、获取队头元素
在获取元素时,队列不能为空。
获取队头元素,只需要使用队头指针即可,
代码如下,
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->phead->data;
}
2.7、获取队尾元素
获取队尾元素,只需要使用队尾指针即可,
代码如下,
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->ptail->data;
}
2.8、获取队列有效元素个数
队列有效元素个数,就是size。
代码如下,
QDataType QueueSize(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->size;
}
2.9、销毁
队列的销毁其实就是链表的销毁,遍历链表一个一个销毁就好了,
代码如下
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
QNode* curNext = NULL;
while (cur)
{
curNext = cur->next;
free(cur);
cur = curNext;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
结束。。。。