栈
(1)栈(后进先出)的两种实现方式:指针和表
用指针方式实现栈的基本操作:
createStack(void)
//.h文件
#ifndef _Stack_h_
struct Node
{
ElementType Element;
PtrToNode next;//节点类型的指针
};
struct Node;
typedef struct Node* PtrToNode;
typedef PtrToNode Stack;
#endif
stack createStack(void)
{
Stack S;
S = malloc(sizeof(struct Node));
if(S == NULL)//申请内存空间失败
FatalError("out of space");
else
MakeEmpty(S);
return S;
}
在MakeEmpty中若栈不为空则不停出栈直到栈为空
void MakeEmpty(Stack S)
{
if(S == NULL)
Error("Must use Created Stack");
else
while(!isEmpty(S))
Pop(S);
}
//判断栈是否为空
int isEmpty(S)
{
return S->next == NULL;
}
入栈和出栈的基本操作(重要),此处的栈都有一个头结点
void Push(ElmentType x,Stack S)
{
PtrToNode TmpCell;//创建一个待插入的临时节点
TmpCell = malloc(sizeof(struct Node));//为这个临时节点分配空间
if(TmpCell == NULL)
FatalError("out of space");
else
{
TmpCell->Element = x;
TmpCell->next = S->next;
S->next = TmpCell;
}
}
void Pop(Stack S)
{
PtrToNode FirstCell;
if(!isEmpty(S))
Error("Empty stack");
else
{
FirstCell = S->next;
S->next = S->next->next;
free(FirstCell);
}
}
二、栈的应用–表达式求值
如何将表达式变为后缀表达式
中缀表达式:a+b * c+(d * e+f) * g
转化为后缀表达式:abc* + de * f+g * +
转化过程:当读取的是一个操作数的时候立即输出,如果是操作符的话,存入栈中,若是左括号,也要存入栈中,
(1)读取到左括号,将栈中元素弹出并输出,直到弹出的是左括号(注意只弹出但是不输出)
(2)如果读取到的是其他的符号(“+”,“-”,“*”,“\”,“(”),当前栈顶的优先级高于要进栈的这个元素,则从栈中弹出元素直到遇到优先级更低的符号为止,然后该元素入栈(注意:除非是遇到),否则(不会弹出的,也就是默认(优先级最高)
略过中间描述过程,用此方法得到后缀表达式。
表达式求值的时候:利用得到的后缀表达式,看见数字就入栈,遇到运算符就从栈中弹出两个数字,计算求得结果,并将结果重新压回到栈中。
尾递归有时候并不恰当,有可能因为数据量过于庞大使得堆栈溢出。
费递归的程序一般来说确实比等价的递归程序要快,但是速度优势的代价却是由于递归而使得程序清晰性变得不足。
队列
队列的特点:头删尾插,顺序队列保留数组Queue[],front,rear
尾部插入:rear和size都加1,置Queue[rear] = X
头部删除:size减1,front加1,返回值为Queue[front]
普通队列不论删除还是插入,front和rear的值都是不断增大的,很容易到达数组的尾部,改进方法:使用循环队列
循环队列:队列空:rear = front-1