首页 > 其他分享 >数据结构学习笔记

数据结构学习笔记

时间:2024-12-04 18:57:16浏览次数:5  
标签:return int 笔记 学习 队列 front 数据结构 data rear

……接上文

4.2 顺序栈

4.2.2 代码实现

头文件seqstack.h:

#ifndef __SEQSTACK_H__
#define __SEQSTACK_H__

typedef int datatype;
typedef struct seqstack
{
    datatype *data; //指向栈的存储位置
    int maxlen;     //保存栈的最大长度
    int top;        //称为栈针,用的时候可以当作顺序表里的last来使用
                    //top始终代表当前栈内最后一个有效元素的下标
} seqstack_t;

//1.创建一个空栈,len代表创建栈时的最大长度。
seqstack_t *createEmptySeqStack(int len);
//2.判断是否为满,满返回1 未满返回0
int isFullSeqStack(seqstack_t *p);
//3.入栈,data代表入栈的数据
int pushStack(seqstack_t *p, int data);
//4.判断栈是否为空
int isEmptySeqStack(seqstack_t *p);
//5.出栈,返回出栈数据
int popSeqStack(seqstack_t *p);
//6. 清空栈
void clearSeqStack(seqstack_t *p);
//7. 获取栈顶数据(注意不是出栈操作,如果出栈,相当于删除了栈顶数据,只是将栈顶的数据获取到,不需要移动栈针)
int getTopSeqStack(seqstack_t *p);
//8. 求栈的长度,返回长度。
int lengthSeqStack(seqstack_t *p);
#endif

3)  入栈

//3.入栈,data代表入栈的数据
int pushStack(seqstack_t *p, int data)
{
    // 1. 容错判断
    if(isFullSeqStack(p))
    {
        perror("pushStack: isFullSeqStack");
        return -1;
    }
    // 2. 往上移动栈针
    p->top++;
    // 3. 将数据入栈
    p->data[p->top] = data;
}

4)  判断是否为空

//4.判断栈是否为空
int isEmptySeqStack(seqstack_t *p)
{
    return p->top == -1;
}

5)  出栈

//5.出栈,返回出栈数据
int popSeqStack(seqstack_t *p)
{
    // int data = p->data[p->top];
    // p->top--;
    // return data;

    // 1. 容错判断
    if(isEmptySeqStack(p))
    { 
        perror("popSeqStack: isEmptySeqStack");
        return -1;
    }
    // 2. 往下移动栈针
    p->top--;
    // 3. 将栈顶数据取出
    return p->data[p->top+1];
}

6)  清空

//6. 清空栈
void clearSeqStack(seqstack_t *p)
{
    p->top = -1;
}

7)  获取栈顶数据

// 7. 获取栈顶数据(注意不是出栈操作,如果出栈,相当于删除了栈顶数据,只是将栈顶的数据获取到,不需要移动栈针)
int getTopSeqStack(seqstack_t *p)
{
    // 1. 容错判断
    if (isEmptySeqStack(p))
    {
        perror("getTopSeqStack: isEmptySeqStack");
        return -1;
    }
    return p->data[p->top];
}

8)  求栈实际长度

//8. 求实际栈的长度,返回长度。
int lengthSeqStack(seqstack_t *p)
{
    return p->top+1;
}

main函数:

int main(int argc, char const *argv[])
{
    seqstack_t *p = createEmptySeqStack(5);
    for (int i = 1; i <= 6; i++)
    {
        pushStack(p, i);
    }
    printf("栈顶是:%d\n", getTopSeqStack(p));

    //只要栈不为空就出栈
    printf("出栈");
    while(!isEmptySeqStack(p))
    {
        printf("%d ", popSeqStack(p)); //出栈的顺序是 5 4 3 2 1 ,因为栈的思想先进后出
    }
    printf("\n");
    
    return 0;
}

练习:

软通动力校园招聘笔试题

1. 若进栈顺序为 1,2,3,4 一下四种情况不可能出现的出栈序列是( )

  A.  1,4,3,2    

  B.  2,3,4,1    

  C.  3,1,4,2

  D.  3,4,2,1

C

2.  下列叙述正确的是( )

A. 线性表是线性结构

B. 栈与队列是非线性结构

C. 线性链表是非线性结构

D.  二叉树是线性结构

A

3. 下列关于栈叙述正确的是( )

    A.在栈中只能插入数据

    B.在栈中只能删除数据

    C.栈是先进先出的线性表

    D.栈是先进后出的线性表

D

4.  请问下面的程序有问题吗?如果有问题在哪儿?

#include <stdio.h>
#include <stdlib.h>
void get_memory(int *q) 
{
    q = (int *)malloc(sizeof(int));
}

int main()
{
    int i;
    int *p = NULL;
    get_memory(p); 
    for(i = 0; i < 10; i++)
    {
        p[i] = i;
    }
    for(i = 0; i < 10; i++)
    {
        printf("%d\n", p[i]);
    }   
    return 0;
}

错误:相当于值传递,并且开辟的空间大小不够用

修改:可以通过传递二级指针,或者返回值。

#include <stdio.h>
#include <stdlib.h>
void get_memory(int **q) 
{
    *q = (int *)malloc(sizeof(int) * 10);
}

int main()
{
    int i;
    int *p = NULL;
    get_memory(&p); 
    for(i = 0; i < 10; i++)
    {
        p[i] = i;
    }
    for(i = 0; i < 10; i++)
    {
        printf("%d\n", p[i]);
    }   
    free(p);
    p=NULL;
    return 0;
}

4.3 链式栈

4.3.1 特性

逻辑结构:线性结构

存储结构:链式存储

顺序栈和链式栈的区别:存储结构不同,实现的方式不同,顺序栈用顺序表实现而链栈用链表实现。

栈的操作:创建、入栈、出栈、清空、获取

4.3.2 代码实现

头节点:

#ifndef __LINKSTACK_H__
#define __LINKSTACK_H__
typedef int datatype;
typedef struct linkstack
{
    datatype data;
    struct linkstack *next;
} linkstack_t;
//1.创建一个空的栈
void createEmptyLinkStack(linkstack_t **ptop);
//2.入栈,ptop是传入的栈针的地址,data是入栈的数据
int pushLinkStack(linkstack_t **ptop, datatype data);
//3.判断栈是否为空
int isEmptyLinkStack(linkstack_t *top);
//4.出栈
datatype popLinkStack(linkstack_t **ptop);
//5.清空栈
void clearLinkStack(linkstack_t **ptop);
//6.求栈的长度
int lengthLinkStack(linkstack_t *top);
//7.获取栈顶数据,不是出栈,不需要移动main函数中的top,所以用一级指针
datatype getTopLinkStack(linkstack_t *top);
#endif

a)  创建一个

//1.创建一个空的栈
void createEmptyLinkStack(linkstack_t **ptop)
{
    *ptop = NULL;
}

b)  入栈ptop是传入的栈针的地址,data是入栈的数

//2.入栈,ptop是传入的栈针的地址,data是入栈的数据
int pushLinkStack(linkstack_t **ptop, datatype data)
{
    // 1. 创建一个新节点保存即将入栈的数据
    linkstack_t *pnew = (linkstack_t *)malloc(sizeof(linkstack_t));
    // 2. 申请节点空间就是为了data
    pnew->data = data;
    // 3. 将新节点插入无头链表的头
    pnew->next = *ptop;
    // 4. 移动栈针,栈针top永远指向无头单向链表的头
    *ptop = pnew;
    
    return 0;
}

c)  判断栈是否为空

//3.判断栈是否为空
int isEmptyLinkStack(linkstack_t *top)
{
    return top == NULL;
}

d)  出栈

//4.出栈
datatype popLinkStack(linkstack_t **ptop)
{
    linkstack_t *pdel = NULL;
    // 1. 容错判断
    if(isEmptyLinkStack(*ptop))
    {
        perror("isEmptyLinkStack!!!");
        return -1;
    }
    // 2. 定义一个pdel指针,指向被删除的节点也就是栈顶的第一个节点
    pdel = *ptop;
    // 3. 定义一个临时变量,保存出栈的数据,也就是保存栈针所指节点中的数据域
    datatype temp = (*ptop)->data;
    // 4. 跨过删除节点,将栈针即头指针向后移动一个位置
    (*ptop) = (*ptop)->next;
    // 5. 释放被删除节点
    free(pdel);
    pdel = NULL;

    // 6. 返回出栈数据
    return temp;
}

e)  清空

//5.清空栈
void clearLinkStack(linkstack_t **ptop)
{
    while(!isEmptyLinkStack(*ptop))
        popLinkStack(ptop);
}

f)  求栈长度

//6.求栈的长度
int lengthLinkStack(linkstack_t *top)
{
    int len = 0;
    while(top != NULL)
    {
        len++;
        top = top->next;
    }
    return len;
}

g)  获取栈顶数据

//7.获取栈顶数据,不是出栈,不需要移动main函数中的top,所以用一级指针
datatype getTopLinkStack(linkstack_t *top)
{
    if(isEmptyLinkStack(top))
    {
        printf("getTopLinkStack: isEmptyLinkStack");
        return -1;
    }
    return top->data;
}

总结:

顺序栈和链式栈的区别是什么?

(1)  存储结构不同:顺序栈是顺序存储,内存连续;链式栈是链式存储,内存不连续。

(2)  顺序栈的长度受限制,而链栈不会。

5.  队列

5.1 特性

队列是只允许再两端进行插入和删除操作的线性表,在队尾插入,在队头删除,插入的一段被称为“队尾”,删除的一端被称为“队头”。队列包括顺序队列(循环队列)、链式队列。

结构:先进先出FIFO

操作:创建、入列、出列、判断是否为空、判断是否为满、清空。

注意:为了避免假溢出问题,即队列前面还有空闲,但是队尾已经出现越界,所以在实际使用队列时,为了使队列空间能重复使用,往往对队列的使用方法稍加改进,需要引入循环队列。一般顺序队列也指循环队列。

循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。

5.2 循环队列(顺序队列)

逻辑结构:线性结构

存储结构:顺序存储结构

操作:创建、入列、出列、判空和满、清空

#define N 6

typedef int datatype;
typedef struct
{
	datatype data[N];//循环队列的数组
	int rear;//存数据端 rear 后面
    int front;//取数据端 front 前面
}sequeue_t;

利用"模运算" (大家习惯用这个方法)

front==(rear+1)%N;

代码:

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

#define N 6
typedef int datatype;
typedef struct
{
	datatype data[N];//循环队列的数组
	int rear;//存数据端 rear 后面
	int front;//取数据端 front 前面
}sequeue_t;
//循环队列中,假设数组的元素个数为N,那么循环队列中存储最多的数据个数为N-1个


// 创建一个空队列
sequeue_t *createEmptySequeue()
{
    sequeue_t *p = (sequeue_t *)malloc(sizeof(sequeue_t));
    if(p == NULL)
    {
        perror("createEmptySequeue malloc failed");
        return NULL;
    }
    p->rear = 0;  // 使用时是数组的下标  尾
    p->front = 0; // 使用时是数组的下标  头

    return p;
}

// 判断队列是否为满
int isFullSequeue(sequeue_t *p)
{
    //思想上,舍去数组上的一个存储位置,用于判断队列是否为满
	//先判断rear的下一个位置是否等于front
    return (p->rear + 1) % N == p->front;
}

//入列 data代表入列的数据
int inSequeue(sequeue_t *p,datatype data)
{
    // 1. 容错判断
    if(isFullSequeue(p))
    {
        perror("isFullSequeue!!");
        return -1;
    }
    // 2. 入列,对尾rear移动
    p->data[p->rear] = data;
    p->rear = (p->rear + 1) % N;
}

//判断队列是否为空
int isEmptySequeue(sequeue_t *p)
{
    return p->rear == p->front;
}

//出列 
datatype outSequeue(sequeue_t *p)
{
    datatype temp; // 临时保存即将出列的数据
    // 1. 容错判断
    if(isEmptySequeue(p))
    {
        perror("isEmptySequeue!!!");
        return -1;
    }
    // 2. 出列数据:思想是先取出数据,然后front向后移动
        // 1) 取出数据
        temp = p->data[p->front];
        // 2) 移动对头 front
        p->front = (p->front + 1) % N;

    return temp;
}

//清空队列函数
void clearSequeue(sequeue_t *p)
{
    // 思想,只要队列不为空,就出列
    while(!isEmptySequeue(p))
        outSequeue(p);
}

//求队列实际的长度
int lengthSequeue(sequeue_t *p)
{
    // 长度情况分为 rear >= front
    //            rear < front
    if(p->rear >= p->front)
    {
        return p->rear - p->front;
    }
    else
        return p->rear + N - p->front;
}

int main(int argc, char const *argv[])
{
    sequeue_t *p = createEmptySequeue();
    for (int i = 1; i <= N-1; i++)
    {
        inSequeue(p, i);
    }
    printf("len is %d \n", lengthSequeue(p));
    printf("rear is %d front is %d\n", p->rear, p->front);
    outSequeue(p);
    outSequeue(p);
    printf("len is %d \n", lengthSequeue(p));
    inSequeue(p, 100);
    printf("len is %d \n", lengthSequeue(p));
    printf("rear is %d front is %d\n", p->rear, p->front);

    while(!isEmptySequeue(p))
        printf("%d ", outSequeue(p));
    printf("\n");
    
    return 0;
}

循环队列,如果数组的元素个数为N,那么队列中最多能够存储的数据数的多少? N-1个  为什么?

答:rear 后面 队尾,在插入的时候,插入之前需要先判断 rear+1,也就是他的下一个为位置是否 等于 front 来判断队列是否为满,会造成浪费一个存储位置。

5.3 链式队列

逻辑结构:线性结构

存储结构:链式结构

操作:创建、入列、出列、判空、清空

队列结构体:

typedef int datatype;
typedef struct node_t
{
    datatype data;
    struct node_t *next;
} linkqueue_node_t, *linkqueue_list_t;

typedef struct //将队列头指针和尾指针封装到一个结构体里
{
    linkqueue_list_t front; //相当于队列的头指针
    linkqueue_list_t rear;  //相当于队列的尾指针
                            //有了链表的头指针和尾指针,那么我们就可以操作这个链表
} linkqueue_t;
 

建立空队列:

代码:

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

typedef int datatype;
typedef struct node_t
{
    datatype data;
    struct node_t *next;
} linkqueue_node_t, *linkqueue_list_t;

typedef struct //将队列头指针和尾指针封装到一个结构体里
{
    linkqueue_list_t front; //相当于队列的头指针
    linkqueue_list_t rear;  //相当于队列的尾指针
                            //有了链表的头指针和尾指针,那么我们就可以操作这个链表
} linkqueue_t;

// 1. 创建一个空的队列,用有头链表
linkqueue_t *createEmptyLinkQueue()
{
    // 1) 申请队列空间,就是为了装东西
    linkqueue_t *p = (linkqueue_t *)malloc(sizeof(linkqueue_t));
    if (NULL == p)
    {
        perror("createEmptyLinkQueue p malloc err");
        return NULL;
    }

    // 2) 申请链表的头节点空间,让rear和front都指向头结点
    p->front = p->rear = (linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
    if (NULL == p->rear)
    {
        perror("createEmptyLinkQueue p->front malloc err");
        return NULL;
    }

    // 可以将 p->front 当作h
    // 可以将 p->rear 当作 ptail
    p->rear->next = NULL;

    return p;
}

//2.入列 data代表入列的数据
int inLinkQueue(linkqueue_t *p, datatype data)
{
    //1.创建一个新的节点,用来保存即将插入的数据
    linkqueue_list_t pnew = (linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
    
    //2.将入列的数据放入到新的节点中
    pnew->data = data;
    pnew->next = NULL;

    //3.将新节点链链接到链表的尾巴
    p->rear->next = pnew;  // 新节点链接到链表的尾
    p->rear = pnew;         //rear移动,因为rear永远指向当前链表的尾

    return 0;
}

//4.判断队列是否为空
int isEmptyLinkQueue(linkqueue_t *p)
{
    return p->rear == p->front;
}

int main(int argc, char const *argv[])
{
    /* code */
    return 0;
}

                                                                                                                               未完待续……

标签:return,int,笔记,学习,队列,front,数据结构,data,rear
From: https://blog.csdn.net/m0_64412253/article/details/144247267

相关文章

  • 数据结构(2)——顺序表的模拟实现
    一:顺序表的认识通过数据结构(1)对于算法复杂度的理解,现在我们正式进入数据结构的核心内容,今天,先来使用C语言实现一下数据结构中最简单的顺序表。首先介绍一下顺序表的概念,先从线性表说起。线性表:n个具有相同结构的数据元素的有限序列。在逻辑结构上一定是线性的,在物理结构上不......
  • Redis——个人笔记留存
    今日内容1.redis1.概念2.下载安装3.命令操作1.数据结构4.持久化操作5.使用Java客户端操作redisRedis1.概念:redis是一款高性能的NOSQL系列的非关系型数据库1.1.什么是NOSQLNoSQL(NoSQL=NotOnlySQL),意即“不仅......
  • git学习
    分支(branch)查看当前所在分支gitbranch查看文件状态(status)查看文件状态gitstatus#代表已修改,但未提交(远程仓库上有该文件)Changesnotstagedforcommit#代表新增的文件(远程仓库上没有该文件)Untrackedfiles切换分支(checkout)如果pro分支已经存在且你需要切换到......
  • YOLOv8-ultralytics-8.2.103部分代码阅读笔记-errors.py
    errors.pyultralytics\utils\errors.py目录errors.py1.所需的库和模块2.classHUBModelError(Exception): 1.所需的库和模块#UltralyticsYOLO......
  • c语言数组学习
    数组数组的概念引例如果我们要在程序中表示一个学生的成绩,我们会使用一个int来表示,如:‘intscore’.假如我们要在程序中表示一组成绩,此时我们所学的常规的数据类型就无法在表示,这个时候我们就需要使用到一种新的表现形式,这种表现形式就是我们的数组。什么是数组数组是......
  • 继电器测试的培训和学习资源有哪些推荐?
    继电器是电气控制设备中常见的一种元件,用于实现电路的开关控制和保护功能。对于从事电气相关工作的人员来说,掌握继电器的测试技能是非常重要的。以下是一些推荐的继电器测试培训和学习资源:在线课程:许多在线学习平台提供了继电器测试的在线课程,如Coursera、Udemy和edX等。这些课......
  • kubernetes菜鸟学习笔记
    目录环境准备dockerminikube启动minikube其他命令kubectlkubernetesdashboardKubernetesPodDeployment自动扩缩容升级版本版本回退探针探针配置项启动探针(startupProbe)就绪探针(readinessProbe)存活探针(livenessProbe)配置示例Service示例Service和Ingress的区别Ingress示例N......
  • 【研一小白零基础学习C语言(六)】
    零基础学习C语言(六)文章目录零基础学习C语言(六)一、随机数的生成二、有范围的随机数生成三、数组基础概念一维数组的创建和初始化一维数组的索引一维数组计算一、随机数的生成随机数生成使用rand()函数,rand函数会返回一个伪随机数,这个随机数的范围是在0~32767之间(......
  • 求教0基础入门大模型的学习路线?java出身,数学良好,希望入局大模型算法,有无必要从cnn学起
    目录前排提示,文末有大模型AGI-CSDN独家资料包哦!前言本人本科学历java开发出身,数学基础良好,希望入局大模型算法,有无必要从cnn学起?transformer、bert是否必须要学?希望能在最短的时间掌握相关知识…近年来,随着大模型的火爆,他的领域几乎涉及到了生活中的方方面面:那么如何快......
  • 大模型(LLMs)学习笔记——基础知识
    目录:前排提示,文末有大模型AGI-CSDN独家资料包哦!一.大模型介绍二.LayerNormalization三.激活函数四.Attention五.transformers函数六.损失函数七.相似度函数一.大模型介绍1.目前主流的开源模型体系有哪些?(1)CausalDecoder(因果解码器)介绍:从左到右的单项注......