【数据结构与算法】几种常用的存储结构 |
您所在的位置:网站首页 › 结构图的制作方法有哪几种 › 【数据结构与算法】几种常用的存储结构 |
常用的逻辑线性结构和逻辑非线性结构: 堆栈、队列、线性表、数组、链表、普通的树、二叉树、哈夫曼树。 下面分别介绍这些数据结构的初始化。 //具体源代码看github:https://github.com/xiami-maker/aboutInitialization/tree/master 堆栈堆栈又称为“栈”,是一种线性结构;其最大的特点是:记忆性、先进后出控制堆栈存取数据需要一个“栈顶指针”,通常堆栈还涉及”栈底指针“。 int top; //栈顶指针,下标 int bottom; //栈底指针,下标 top和bottom的初始值都是0,这表示栈为“空”。 入栈的过程,即,push的过程:stack[top++] = data;这就是data入stack栈的过程。 数据出栈的过程,即,pop的过程:data = stack[–top]; 堆栈相对于一般的存储结构,最大的不同点是:其中的数据,不能“遍历”!只能直接访问栈顶元素的值,不能访问栈顶元素下面的元素的值!也就是说,堆栈不支持“随机访问(就是通过下标进行访问!)”。 堆栈的实现: 由于堆栈有空间、栈顶指针等众多要素,因此,先设计其“控制头”; typedef struct MEC_STACK { void **data; int capacity; int top; }MEC_STACK;画图来表示为: 线性逻辑结构,一对一; 基本点:一个入口(队尾)和一个出口(队首) 特点:先进先出 画图表示如下 其中head表示队首,tail表示队尾,lastAction表示上一次操作。 队列满时,heda == tail;队列空时,head == tail; 单独从head == tail,无法判断队列的空与满!但是,可以根据上一次队列的操作(入队列或出队列)来综合判断。 队列中有效元素个数的计算公式: (tail - head + capacity ) % capacity; 具体源代码看最上方的github; 链表链表是一个物理非线性结构。是由一个一个的节点链接而成,每个节点对应一块内存空间,两个节点之间并不是像数组一样连续。 节点的定义如下: typedef struct NODE { void data; struct NODE *next; }NODE;链表形成的链式结构如下图: 树的性质: 1.一棵树最多有一个节点,该节点无前驱节点,即,无父节点,称为:根节点;空树:没有任何节点的树。 2.树中的任意一个节点,有且仅有一个前驱节点,可以有n(n >= 0)个后继节点。 3.若一个节点没有后继节点(子节点),则,这个节点称为“叶子节点”。 树的基本术语: 根节点:如上,不再赘述。 节点的度(degree):一个节点的子节点个数,称为这个节点的度。 树的度:一棵树中,度最大的节点的度,称为该树的度。 树的深度(高度):树的节点的层次数。 叶子节点:度为0的节点。 树的遍历: 哈夫曼树: 由于哈夫曼树涉及到一个非常具有实际意义的问题:哈夫曼压缩与解压缩技术,所以单独写了一篇博文,这里提供博文链接:https://blog.csdn.net/weixin_44836233/article/details/102837718 数组 int arr[10];数组是一个线性结构,其特点: 1.数组通常由capaci的限制; 2.数组中的元素,类型都是一样的;即,数组元素长度相同。 在学习数组时,需要解决的问题是:地址映射。 double ar[10] = {.....};ar[3] 在c编译器的工作下,将转换成:ar + sizeof(double) * 3;这个结果直接在c程序执行时体现,在c语言源代码角度根本看不到这个“地址映射“过程!!! 现在要求编写一个通用二维数组。 typedef struct MATRIX { USER_TYPE *data; int maxRow; int maxCol; }MATRIX;在这个MATRIX所提供的算子(函数)中,最重要的基础函数是:行、列值与一维数组下标的相互转换。 线性表是一个逻辑线性结构,即,一对一结构。 在讨论线性表的实现(存储结构),可以用物理线性结构(数组)实现,也可以用物理非线性结构(链表)实现。 假设用数组实现: 一个简单而目光短浅的做法是:直接用数组就好了(代码如下)!!! typedef struct POINT { int row; int col; }POINT; POINT *pointLinear = NULL; int pointCount = 0; int capacity = 30; pointLinear = (POINT *) calloc(sizeof(POINT),capacity);对于线性表的思考:线性表处理需要必须的“存储空间”(就是线性表的主体部分)之外,还需要对线性表进行诸多方面的运算:插入、删除、查找、清空等等,或者说:控制! “控制头是基于数据(信息)的”,因此,为了更好地控制线性表,也为了能为“用户”(使用我们所编写的线性表工具,完成自己的APP的那些程序员,就是我们的用户!)提供一个我完善的编程工具,需要先定义一个“控制头”! 控制头部分至少有如下三种内容: 1。存储用户数据的线性表空间; 2.线性表的容量; 3.用户数据的数量; 最后一个难题,用户的数据类型!! 因为工具需要具有普适性。工具不能因为用户的数据类型不一致,而不能使用!!!以前曾经用过USER_TYPE的方式解决用户类型的问题,但是,这是需要用户事先定义USER_TYPE类型,且,这个类型只能是一种;这些约束都使得USER_TYPE方式应该慎重使用。 这里将使用void **的方案解决用户数据类型普适化的问题! 假设用户数据类型是:POINT,用数组直接表达的方案,应该如下:POINT data[N];事实上,上述数组的每一个元素的类型是POINT; 如果用动态存储分配的方案实现: POINT *data; data = (POINT *) calloc(sizeof(POINT),capacity); 事实上,上述动态申请的每一个元素类型是POINT; 对于下面的定义,该如何理解? POINT *data[N]; data是一个(拥有N个POINT *类型的元素)数组;所以,data是一个指针数组(由指针组成的数组)! 如果用动态存储分配方案,则写成: POINT **data; data = (POINT **) calloc(sizeof(POINT *),capacity); 这里最关键的问题是:sizeof(POINT *)的结果是4B,而且,无论是否是POINT,任意类型的指针类型,长度都为4B;那么就定义为: void **data; data = (void **) calloc(sizeof(void *),capacity); 当然的,在data[i]中,必须存储而且也只能存储用户数据类型的变量的首地址(指针)! data[i]的类型是void *,是一个指针类型; 综上所述,MEC_LINEAR类型的定义是: typedef struct MEC_LINEAR { void **data; //真正的线性表空间 int capacity; //线性表容量 int count; //有效的用户数据个数 }MEC_LINEAR;线性表的结构图如图所示: |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |