1.栈
栈是一种特殊的线性表,只允许在固定的一段进行插入和删除操作,进行操作的一段称为栈顶,另一端称为栈底。栈中元素遵守先进后出的原则。
压栈:将元素插入栈中,也称进栈,入栈。入栈元素在栈顶。
出栈:栈的删除操作。出栈也在栈顶。
2. 栈的实现
栈的底层结果一般是数组。
2.1 结构体的定义
依旧是将结构体和数据类型重命名便于使用。跟顺序表一样,有一个容量,有一个有效数量,还有一个指向数组的指针。
2.2 初始化栈
将数组置为空并将容量和数量置为0;
2.3 入栈
入栈要分两种情况,第一种是容量不足的情况,即capacity ==top。这种情况下,要开辟新的空间,通过realloc将容量增加,判断申请有效后再将指针指向新空间。第二种是空间充足的情况,则直接将数组下标位top的位置置为x,并将top++。
2.4 出栈
只需要将栈的top判断不为0,则栈有数据,有数据才能出栈。而出栈只需要将top--就可以。
2.5 销毁栈
栈的底层是数组,所以栈的销毁只需要将指针置为0并free掉,然后将top和capacity变为0;
3.基于栈的典型例题
思路:构建栈,遍历字符串,当遇到左括号时,进行入栈操作,当遇到右括号时,进行匹配操作。如果栈顶的元素与右括号匹配,则进行出栈操作,不匹配则进行栈销毁并返回false。当遍历完之后,则判断是否栈为空,若为空则返回true,不为空则返回false。
代码如下:
bool isValid(char* s) {
ST st;
stinit(&st);
char * ps = s;
while(*ps!='\0')
{
if(*ps=='('||*ps =='['||*ps=='{')
{
stpush(&st,*ps);
}
else
{//匹配
if(st.top ==0)
{
stdestroy(&st);
return false;
}
if((*ps=='}'&&gettop(&st)=='{')
||(*ps==']'&&gettop(&st)=='[')
||(*ps==')'&&gettop(&st)=='('))
{
stpop(&st);
}
else//不匹配
{
stdestroy(&st);
return false;
}
}
ps++;
}
if(st.top!=0)
{
stdestroy(&st);
return false;
}
stdestroy(&st);
return true;
}
4. 队列
队列是只允许在一段进行插入数据,在另一端进行删除数据操作的特殊线性表,它的特点是先进先出。在队头进行出队操作,在队尾进行入队操作。
5. 队列的实现
5.1 结构体的定义
队列的底层一般是单链表。
为了更好的在链表中实现队的操作,队列的结构体需要一个头结点和一个尾结点,以及一个记录有效个数的size。而头结点和尾结点则是结点结构体,包含一个结构体指针和一个数值。
5.2 队列的初始化
初始化就是将队列的各个指针置为空,数据置为0.
5.3 入队
入队需要分两种情况,当原队列中没有元素时,头尾指针都等于新结点。当队列中有元素时,则直接将newnode结点接在尾结点的后面,再将新节点置为尾结点。
5.4 出队
出队需要判断队列是否为空。出队从队头出,直接就是将头结点变为第二个结点,再把之前的头结点free掉,但是其实还需要考虑,如果只有一个元素,将头结点free了之后,尾结点此时也指向的头结点,因此我们需要单独考虑只有一种元素的情况。这种情况下,我们要将两个结点都置为空。
5.5 销毁队列
销毁队列需要判断队列是否为空。空队列不能销毁。销毁队列就是遍历队列,将每个结点都free掉并将头尾结点置为空,size变为0。