数据结构(二)—— 栈,队列,广义表

本文详细介绍了数据结构中的栈和队列,包括它们的定义、基本操作以及实现方式,如顺序栈、链栈、顺序队列和链队列。还探讨了括号匹配和表达式求值等实际应用,并引入了双端队列的概念。此外,讨论了栈和队列在树的层次遍历、图的广度优先遍历以及矩阵压缩存储等领域的应用。
摘要由CSDN通过智能技术生成

第2章 栈,队列,数组

定义

只允许在一端进行插入或删除操作的线性表。
在这里插入图片描述

基本操作

InitStack(&S)初始化栈。构造一个空栈S,分配内存空间。
DestroyStack(& S)销毁栈,并释放栈S所占用的空间。
Push(&S,x)进栈,若栈S未满,则将x加入使之成为新栈顶。
Pop(&S,&x)出栈,若栈S非空,则弹出栈顶元素,并用x返回。
GetTop(S,&x)读取栈顶元素。若栈S非空,则用x返回栈顶元素。
其他常用操作:
StackEmpty(S):判断一个栈S是否为空。若S为空,则返回true,否则返回false。

顺序栈

定义
#define MaxSize 10
typedef struct {
    ElemType data[MaxSize];		//静态数组存放栈中元素
    int top;					//当前栈顶指针位置
}SqStack;

Tips:注意栈顶指针top的含义。

基本操作——初始化
//初始化
void InitStack(SqStack &S) {
    S.top = -1;
}
基本操作——进栈
bool Push(SqStack &S,ElemType x) {
    if(S.top == MaxSize -1)		//栈满
        return false;
    S.top ++;
    S.data[S.top] = x;		//进栈
    //S.data[++S.top];
    return true;
}
基本操作——出栈
bool Pop(SqStack &S,ElemType &x) {
    if(S.top == -1)		//栈空
        return false;
    x = S.data[S.top];	//出栈
    S.top --;
    //x = S.data[S.top--];
    return true;
}
基本操作——读取栈顶元素
bool GetTop(SqStack &S,ElemType &x) {
    if(S.top == -1)		//栈空
        return false;
    x = S.data[S.top];	//x记录栈顶元素
    return true;
}

链栈

在这里插入图片描述

栈的应用
括号匹配
/* 算法思想:依次输入表达式字符,若是左括号,将其入栈,若是右括号,则出栈一左括号与其匹配,循环执行,直到表达式输入结束。若表达式中所有括号都能被匹配,则表达式括号匹配正确,否则不正确。 */
bool BracketCheck(char str[],int length) {
    SqStack S;
    InitStack(S);	//初始化一个栈
    for(int i = 0;i < length;i++){
        if(str[i] == '(' || str[i] == '[' || str[i] == '{') {
            Push(S,str[i]);		//扫描到左括号,入栈
        }
        else{
            if(StackEmpty(S))	//扫描到右括号,且当前栈空,则匹配失败
        		return false;
            char topelem;
            Pop(S,topElem);		//栈顶元素出栈
            if(str[i] == ')' && topElem != '(')
                return false;
            if(str[i] == ']' && topElem != '[')
                return false;
            if(str[i] == '}' && topElem != '{')
                return false;
        }
    }
    return StackEmpty(S);	//检查完全部括号后栈空,则说明配对成功
}
表达式求值

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

队列

定义

只允许在一端进项插入,在另一端删除的线性表。
在这里插入图片描述

基本操作

InitQueue(&Q)初始化队列,构造一个空队列Q。
DestroyQueue(&Q)销毁队列。销毁并释放队列Q所占用的空间。
EnQueue(&Q,x)入队,若队列未满,将x加入,使之成为新的队尾。
DeQueue(&Q,&x)出队,若队列Q非空,删除队头元素,并用x返回。
其他常用操作:
GetHead(Q,&x):读取队头元素,若队列Q非空,则将队头元素赋给x。
QueueEmpty(Q):判断队列是否为空,若队列为空返回true,否则返回false;

顺序队列

定义
#define MaxSize 10
typedef struct {
    ElemType data[MaxSize];		//用静态数组存放队列元素
    int front,rear;				//队尾指针指向队尾元素后一个位置
}SqQueue;
基本操作——初始化
void InitQueue(SqQueue &Q) {
    Q.rear = Q.front = 0;		//队空条件
}
基本操作——入队
bppl EnQueue(SqQueue &Q) {
    if(Q.rear == Q.front)		//判断队满
    	return false;
    Q.data[Q.rear] = x;
    Q.rear = (Q.rear + 1) % MaxSize;	//模运算使存储空间在逻辑上变成了“环”
    return true;
}

在这里插入图片描述

其他判断队空/队满条件

(1)在不牺牲存储单元的情况下可以在结构体设置int size记录队列长度,根据长度进行判断队空和队满。
(2)在这里插入图片描述

基本操作——出队
bool DeQueue(SqQueue &Q,ElemType &x) {
    if(Q.rear == Q.front)
        return false;	//判断队空
    x = Q.data[Q.front];
    Q.front = (Q.front + 1) % MaxSize;
    return true;
}
基本操作——读取队头元素
bool GetHead(SqQueue Q,ElemType &x) {
    if(Q.rear == Q.front)
        return false;	//判断队空
    x = Q.data[Q.front];
    return true;
}

Tips:队列元素个数 = (rear + MaxSize - front) % MaxSize

链队列

定义
typedef struct LinkNode {	//链式队列结点
    ElemType data;
    struct LinkNode *next;
}LinkNode;

typedef struct {			//链式队列
    LinkNode *front,*rear;	//队列的队头和队尾指针	
}LinkQueue;
基本操作——初始化
/* 带头结点 */
void InitQueue(LinkQueue &Q) {
    /* 均可以作为判空条件 */
	Q.front = Q.rear = (LinkNode)malloc(sizeof(LinkNode));
    Q->front->next = NULL;
}

/* 不带头结点 */
void InitQueue(LinkQueue &Q) {
	Q.front = NULL;		
    Q.rear = NULL;
}
基本操作——入队
/* 带头结点 */
void EnQueue(LinkQueue &Q,ElemType x) {
	LinkNode *s = (LinkNode*) malloc(sizeof(LinkNode));
    s->data = x;
    s->next = NULL;
    Q.rear->next = s;
    Q.rear = s;
}

/* 不带头结点 */
void EnQueue(LinkQueue &Q,ElemType x) {
	LinkNode *s = (LinkNode*) malloc(sizeof(LinkNode));
    s->data = x;
    s->next = NULL;
    if(Q.front == NULL) {		//空队列插入第一个元素
        Q.front = s;
        Q.rear = s;
    }
    else{
    	Q.rear->next = s;
    	Q.rear = s;
	}
}
基本操作——出队
/* 带头结点 */
bool DeQueue(LinkQueue &Q,ElemType &x) {
    if(Q.front == Q.rear)		//空队
        return false;	
    LinkNode *p = Q.front->next;
    x = p->data;
    Q.front->next = p->next;
    if(Q.rear == p)		//此次是最后一个结点出队
        Q.rear = Q.front;
    free(p);
    return true;
}

/* 不带头结点 */
bool DeQueue(LinkQueue &Q,ElemType &x) {
	if(Q.front == NULL)		//空队
        return false;
    LinkNode *p = Q.front;
    x = p->data;
    Q.front = p->next;
    if(Q.rear == p) { 		//此次是最后一个结点出队
    	Q.front = NULL;
        Q.rear = NULL;
    }
    free(p);
    return true;
}

Tips:一般不会出现队满情况。

双端队列

允许在两端插入、两端删除的线性表。(输入受限/输出受限)
Tips:在栈中合法的输出序列,在双端序列必定合法。

队列的应用

  • 树的层次遍历
  • 图的广度优先遍历

矩阵的压缩存储

对称矩阵

在这里插入图片描述
在这里插入图片描述
Q:数组大小应为多少?
A:(n + 1)* n / 2

上三角矩阵

在这里插入图片描述

三对角矩阵

在这里插入图片描述
在这里插入图片描述

稀疏矩阵

在这里插入图片描述
在这里插入图片描述

广义表

  • 广义表是具有n个元素的有限序列,记为LS = (a1,a2,……an)。
  • 一个广义表通常可以用一对圆括号括起来,n是它的长度。
  • ai可以是单个元素,也可以是广义表,分别叫原子和子表(子表也要用圆括号括起来)。
  • 用大写字母表示广义表的结构名,用小写字母表示原子。
  • 广义表非空时,第一个元素a1为LS的表头(head),其余元素组成的表(a2,a3,……an)是LS的表尾(tail)。
    • A = () —— A是一个空表,长度为零。
    • B = (e) —— 列表B只有一个原子e,B的长度为1。
    • C = (a,(b,c,d)) —— 列表C的长度为2,两个元素分别为原子a和子表(b,c,d)。
    • D = (A,B,C) —— 列表D的长度为3,三个元素都是列表。
    • E = (a,E) —— 这是一个递归的表,长度为2。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值