数据结构的概述
定义
我们如何把现实中大量而反复的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排序)而执行的相应的操作,这个相应的操作也叫做算法。
数据结构=个体+个体的关系
算法=对存储数据的操作
狭义:
数据结构是专门研究数据存储的问题
数据的存储包含两方面:个体的存储 + 个体关系的存储
广义:
数据结构既包含数据的存储也包含数据的操作
对存储数据的操作就是算法
算法
狭义:
算法是和数据的存储方式密切相关
广义:
算法和数据的存储方式无关,这就是泛型思想
衡量算法的标准:
(1)时间复杂度
大概程序要执行的次数,而并非是执行的时间(因为同一程序在不同机器上执行的时间是不一样的,有差异)
(2)空间复杂度
算法执行过程中大概所占用的最大内存
(3)难易程度
(4)健壮性
数据结构的地位:
数据结构是软件中最核心的课程
程序 = 数据的存储 + 数据的操作 + 可以被计算机执行的语言
泛型
对于同一种逻辑结构,无论该逻辑结构的物理存储是什么样子的,我们可以对它执行相同的操作。
数据的存储有几种:
线性:
连续存储:【数组】
优点:存取速度快
缺点:
事先必须知道数组的长度
插入删除元素很慢
空间通常是有限的
需要大块连续的内存块
离散存储【链表】
优点:
空间没有限制
插入删除元素很快
缺点:
存取速度很慢
栈和队列是一种特殊的线性结构,是连续存储或离散存储的一种应用
线性结构的应用------栈
定义:
一种可以实现“先进后出“的存储结构,类似于箱子
分类:
静态栈
动态栈
算法:
出栈
压栈
应用:
函数调用
中断
表达式求值
内存分配
缓冲处理
迷宫
int main(void)
{
int p;
int * m = (int *)malloc(100);
}
如静态变量p和m是在栈中分配,有操作系统自动分配和释放。而(int *)malloc(100);执行后,将在堆中分配一块100字节的内存,由程序员手动分配。
栈的示意图
线性结构的应用------队列
定义:
一种可以实现“先进先出”的存储结构
分类:
链式队列: -----用链表实现(比较简单)
静态队列: -----用数组实现 静态队列通常都必须是循环队列
应用:
所有和时间有关的事件都有队列的影子
循环队列的讲解
(1)静态队列为什么必须是循环队列
现在如果一个数组里面存了四个元素,那么front就只想第一个有效元素,而real指向最后一个元素的下一个元素,当增加元素时,只能在rear一端增加,即rear向上移。删除元素时,只能在front一端删除元素,即front向上移。但是如果一直增增删删,那么就会造成rear端溢出,而front端浪费,所以对于这种情况,可以采用循环队列的形式,即当rear已经指向数组最后一个元素时,那么就可以转而将rear指向数组的第一个空出来的空间。
(2)循环队列需要几个参数来确定
需要2个参数来确定:front 和 rear
(3)循环队列各个参数的含义:
2个参数在不同场合有不同的含义
队列初始化
front和rear的值都为零
队列非空
front代表的是队列的第一个元素
rear代表的是队列的最后一个有效元素的下一个元素
队列为空
front和real的值相等,但不一定为零
(4)循环队列入队伪算法讲解:
两步完成:
将值存入rear所代表的位置
错误的写法 :rear = rear+1;
正确的写法是:rear = (rear+1)%数组的长度
(5)循环队列出队伪算法讲解
Front =(front +1)%数组的长度
(6) 如何判断循环队列是否为空
如果front与rear的值相等,则该队列就一定为空
(7)如何判断循环队列是否已满
因为front的值可能比rear大,也可能比他小,也可能相等
所以有两种方式:
多增加一个标识是否满的参数
少用一个元素【通常用此种方式】
如果front和rear的值相差1,且front>rear,则证明队列已满。
用C语言伪算法表示为:
if ((rear+1)%数组长度==front)
已满
else
未满