目录
栈
栈的基本概念
还有一个鲜明的例子:把栈想象成洗碗,只能在叠起来的碗的最高处拿或放(不过栈不能同时拿或放多个碗)
栈:限定仅在表尾(栈顶)进行插入或删除操作的线性表 表头(栈底)
不含元素的空表称空栈
特点:先进后出(先进栈的后出栈)first in late out (FILO)
后进先出(后进栈的先出栈)late in first out (LIFO)
逻辑结构:一对一
存储结构:顺序/链栈
栈的输出序列
举个例子:利用一个栈,如果输入序列由A,B,C组成。
通过栈可以实现如下输出:
A入,A出,B入,B出,C入,C出。(ABC)
A入,A出,B入,C入,C出,B出。(ACB)
A入,B入,B出,A出,C入,C出。(BAC)
那么问题来了:
利用一个栈,如果输入序列由A → B → C组成,试找出不可能实现的输出序列?(已经排除一个错误答案啦)
- B → A → C
- C → B → A
- C → A → B
- B → C → A
答案是3.
存储结构:顺序栈
#define MaxSize 100
typedef struct
{
int *base; //栈底指针
int *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
//初始化
int InitStack( SqStack &s)
{
s.base = new int [MaxSize]; // 申请存储空间
if ( !s.base ) return -1;
s.top = s.base; // top初始为base,表示栈为空
s.stacksize = MaxSize; // 最大容量
return 1;
}
//入栈
int Push( SqStack &s, int e )
{
if ( s.top – s.base >= s.stacksize )
return -1;
*s.top++ = e; // 从栈底开始录入,所以自增后置
return 1;
}
//出栈
int Pop(SqStack &s, int &e )
{
if ( s.top == s.base )
return -1;
e = *--s.top; // 出栈前s.top指针指向的是空值
// --s.top才是指向要出栈的值
return 1;
}
注:top 指向真正的栈顶元素之上的下标地址
ps:要注意自增和自减的位置
存储结构:链栈
只能在链表头部进行操作,故没有必要附加头结点,栈顶指针就是链表的头指针。
//结点定义
typedef struct StackNode
{
int data; //数据域
struct StackNode *next; //指针域
} StackNode, *LinkStack;
//初始化
int InitStack(LinkStack &S )
{
S = NULL;
return 1;
}
//入栈
int Push ( LinkStack &S, int e )
{
StackNode *p;
p=new StackNode;
if ( !p ) return -1; // 申请存储空间失败
p -> data = e;
p -> next = S;
S = p;
return 1;
}
//出栈
int Pop ( LinkStack &S, int &e)
{
StackNode *q;
if ( S != NULL ) {
q = S; // 以备释放结点
e = S->data;
S = S->next;
delete q; // 释放结点
return 1;
}
else
return -1;
}
队列
(顾名思义,就是排队伍前面的出去,进来的排队伍后面)
定义:队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表
- 队尾(rear)——允许插入的一端
- 队头(front)——允许删除的一端
队列特点:先进先出(FIFO)
除此之外,还有双端队列(同时具备栈和队列的特性)
队列的顺序表示
实现方式:一维数组
#define MaxQSize 100
typedef struct
{
int *base; //存储空间
int front; //头指针
int rear; //尾指针
}SqQueue;
如下图,队列为空的条件为rear==front ,那么就会存在如下问题:
设数组大小为M,则:
当front=0,rear=M时,再有元素入队发生溢出——真溢出
当front0,rear=M时,再有元素入队发生溢出——假溢出于是,我们将队列设想成环形,若rear+1==M,则令rear=0.
入队: sq[rear]=x; rear=(rear+1)%M;
出队: x=sq[front]; front=(front+1)%M;
以下是循环队列的部分代码
//初始化
int InitQueue( SqQueue &Q )
{
Q.base = new int [MaxQSize]; // 申请空间
if ( !Q.base ) return -1; // 存储分配失败
Q.front = Q.rear = 0; // 头指针和尾指针置零
return 1;
}
//入队
int EnQueue( SqQueue &Q, int e )
{
if ( ( (Q.rear+1) % MaxQSize ) == Q.front )
return -1;
else
{
Q.base[Q.rear] = e; // 在队尾插入
Q.rear=(Q.rear+1) % MaxQSize;
return 1;
}
}
链队列
结点定义
typedef struct QNode
{
int data;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
以下是链队列的部分代码
//入队
int EnQueue( LinkQueue &Q,int e )
{
QueuePtr p;
p= new QNode ;
if ( !p ) return -1 ; // 申请结点失败
p->data = e;
p->next = NULL;
Q.rear->next = p; // 将新结点插入到队尾
Q.rear = p; // 修改队尾指针
return 1;
}
//出队
int DeQueue(LinkQueue &Q, int &e )
{
QueuePtr p;
if( Q.front == Q.rear ) return -1; // 队列为空
p = Q.front->next; // p指向对头元素
e = p->data;
Q.front->next = p->next; // 修改头结点的指针
if ( Q.rear == p )
Q.rear = Q.front; // 队列空时,队尾指针指向头结点
delete p;
return 1;
}
应用(算法思路)
放在社区学习活动(找不到就是我还没放)
参考资料:
1. 数据结构——使用C语言(第5版)
2. 数据结构——C++实现
3. 数据结构与算法 ppt(线性表) 张合生