数据结构学习笔记Day3(连载中)

线性结构的应用

(1)线性结构的两种常见应用之一——栈

1.定义

    一种可以实现"先进后出"的存储结构;

    类似于箱子

2.分类

    态栈

    态栈

3.算法

    出栈

    压栈

4.栈程序示例

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

typedef struct Node{
    int data;//数据域
    struct Node * pNext;
}NODE,*PNODE;

typedef struct Stack{
    PNODE pTop;//指向栈的顶部节点
    PNODE pBottom;//指向栈的底部节点
}STACK,* PSTACK;

//函数声明
void init(PSTACK);//初始化一个空栈,使pTop和pBottom都指向头结点
void push(PSTACK,int);//存元素,压栈
void traverse(PSTACK);//遍历
bool pop(PSTACK,int *);//出栈并且返回出栈元素,还要判断出栈是否成功
bool empty(PSTACK);//判断栈是否为空
void clear(PSTACK);//清空数据

int main(){
    STACK S;//等价于struct Stack S,分配一块内存空间名为S
    //里面有pTop和pBottom,暂时是垃圾值
    int val;

    init(&S);//初始化一个空栈,使pTop和pBottom都指向头结点
    push(&S,1);//存元素,压栈
    push(&S,2);//存元素,压栈
    traverse(&S);//遍历
    //clear(&S);//清空
    //traverse(&S);//遍历

    if(pop(&S,&val)){//删元素,出栈
        printf("出栈成功,出栈元素的是%d\n",val);
    }
    else{
        printf("出栈失败");
    }
    traverse(&S);//遍历

    return 0;
}

void init(PSTACK pS){
    pS->pTop = (PNODE)malloc(sizeof(NODE));

    if(pS->pTop==NULL){
        printf("动态内存分配失败");
        exit(-1);//程序终止
    }
    else{
        pS->pBottom=pS->pTop;//空栈情况下,栈顶和栈底都指向同一个地址
        //即最后一个有效节点的下一个节点
        pS->pTop->pNext=NULL;//pS->pBottom->pNext==NULL
        //pS的成员pTop指向的头结点的指针域为空
    }
}

void push(PSTACK pS,int val){
    PNODE pNew = (PNODE)malloc(sizeof(NODE));//创建新结点
    pNew->data = val;
    pNew->pNext = pS->pTop;//使新节点的指针域指向原来的栈顶节点,
    //不能是ps->pBottom
    pS->pTop = pNew;//使栈顶指向新节点地址

    return ;
}

void traverse(PSTACK pS){
    PNODE p = pS->pTop;//临时指针指向栈顶
    while(p != pS->pBottom){//若p还没有栈底pBottom,则遍历输出
        printf("%d ",p->data);//从栈顶开始输出
        p=p->pNext;
    }
    printf("\n");
    return ;
}

bool empty(PSTACK pS){
    if(pS->pTop == pS->pBottom) return true;//当栈底和栈顶指向同一块地址,为空栈
    else return false;
}

//把pS所指向的栈出栈一次,并把出栈的元素存入val形参所指向的变量中,
//出栈成功返回true,失败返回false
bool pop(PSTACK pS,int * pVal){
    if(empty(pS)) return false;
    else{
            PNODE r = pS->pTop;//临时指针r指向出栈元素位置:栈顶,方便最后释放内存
            *pVal = r->data;//主函数里输出出栈元素
            pS->pTop = r->pNext;//栈顶指针指向原来栈顶的下一个节点地址
            free(r);
            r = NULL;
            return true;
    }
}

void clear(PSTACK pS){//清空数据,最终使栈顶和栈底指向同一个地址
    if(empty(pS)){//如果栈本身为空,不需要清空
        return ;
    }
    else{
        PNODE p = pS->pTop;//临时指针P指向栈顶
        PNODE q = NULL;//临时指针q暂时设为NULL
        while(p != pS->pBottom){//当栈顶指针不指向栈底时,栈不为空
            q = p->pNext;//临时指针q指向下一个节点
            free(p);//释放p的内存
            p = q;//再使p指向下一节点地址
        }
    }
    pS->pTop = pS->pBottom;//最后数据全部清空,栈顶和栈底指向同一个地址
}

5.应用

函数调用

中断

表达式求值

内存分配

缓冲处理

迷宫

(2)线性结构的两种常见应用之二——队列

1.定义

一种可以实现"先进先出"的存储结构

2.分类

链式队列——用链表实现

静态队列——用数组实现

静态队列通常都必须是循环队列

3.循环队列的讲解

①循环队列需要几个参数来确定?

需要2个参数来确定

②循环队列各参数的含义

2个参数在不同场合不同的含义,建议初学者先记住,然后慢慢体会。

    队列初始化:front和real的值都是零

    队列非空:front代表的是队列的第一个元素,real代表的是队列的最后一个有效元素的下一个元素

    队列空:front和real的值相等,但不一定是零

③循环队列入队伪算法讲解

入队伪算法演示(两步完成)

    先将值存入real所代表的位置

    再移动real

× real = real+1; //这样的写法是错误

real = (real+1)%len; //这样的写法是正确的,其中,len为数组长度

④循环队列出队伪算法讲解

出队伪算法演示(一步完成)

front= (front+1)%len;

也可以先把出队的值保存起来,再移动front,通过两部完成

⑤如何判断循环队列是否为空

如果front与real的值相等,则该队列为空。

⑥如何判断循环队列是否已满

预备知识:

front 的值可能比 real 的值

front 的值可能比 real 的值

front 的值和 real 的值当然也可能相等

两种方式判断队列是否已满:

    多增加一个标识参数 或 少用一个元素【通常采用"少用一个元素的方式"】

    如果r和f紧挨着,则队列已满

    用C语言伪算法表示为:

    if ( (r+1)%len == f )
        已满;
    else
        不满;

4.循环队列程序示例

 #include <stdio.h>
    #include <malloc.h>
    
    typedef struct Queue
    {
    	int * pBase;
    	int front;
    	int real;
    }QUEUE;
    
    void init(QUEUE *);
    bool en_queue(QUEUE *, int);	//入队 
    void traverse(QUEUE *);
    bool full_queue(QUEUE *);
    bool empty_queue(QUEUE *);
    bool out_queue(QUEUE *, int *); 
    
    int main(void)
    {
    	QUEUE Q;
    	int val;
    	
    	init(&Q);
    /*
    	en_queue(&Q, 1);
    	en_queue(&Q, 2);
    	en_queue(&Q, 3);
    	en_queue(&Q, 4);
    	en_queue(&Q, 5);	//数组长度为6,只能打印到5 
    	en_queue(&Q, 6);
    	en_queue(&Q, 7);
    */	
    	traverse(&Q);
    	
    	if ( out_queue(&Q, &val) )
    	{
    		printf("出队成功,出队的元素是:%d\n", val);
    	}
    	else
    		printf("出队失败!\n");
    	
    	traverse(&Q);
    	
    	return 0;
    }
    
    void init(QUEUE * pQ)
    {
    	pQ->pBase = (int *)malloc(sizeof(int) * 6);  
    	pQ->front = 0;
    	pQ->real = 0;
    
    }
    
    bool full_queue(QUEUE * pQ)
    {
    	if ((pQ->real + 1) % 6 == pQ->front)
    	{
    		return true;
    	}
    	else
    		return false;
    }
    
    bool en_queue(QUEUE * pQ, int val)
    {
    	if (full_queue(pQ))
    	{
    		return false;
    	}
    	else
    	{
    		pQ->pBase[pQ->real] = val;
    		pQ->real = (pQ->real + 1)  %6;
    		
    		return true;
    	}
    }
    
    void traverse(QUEUE * pQ)
    {
    	int i = pQ->front;
    	
    	while (i != pQ->real)
    	{
    		printf("%d ", pQ->pBase[i]);
    		i = (i + 1) % 6;
    	}
    	printf("\n");
    	
    	return;
    }
    
    bool empty_queue(QUEUE * pQ)
    {
    	if ( pQ->front == pQ->real )
    		return true;
    	else
    		return false;
    }
    
    bool out_queue(QUEUE * pQ, int * pVal)
    {
    	if ( empty_queue(pQ) )
    	{
    		return false;
    	}
    	else
    	{
    		*pVal = pQ->pBase[pQ->front];
    		pQ->front = (pQ->front + 1) % 6;
    		
    		return true;	
    	}
    }

5.队列的应用

    所有和时间有关的操作都有队列的影子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值