数据结构
绪论
0、数据
数据就是能够输入计算机中,并被计算机识别、存储、处理、显示的信息
数据是由数据元素组成
数据元素:是数据的基本单位,数据元素有由若干数据项构成,数据项就是数据元素的最小单位,可以用基本数据类型表示信息的一个属性
1、数据结构的定义
数据结构:研究数据与数据之间的逻辑结构,并研究如何在计算机中存储这种有关系和有关系的数据(存储结构),以及对这些有关系的数据进行操作
2、数据之间的关系分类
分类一
线性关系 (排队)
层次关系 (上下级)
网状关系(地铁线路)
3、数据结构研究内容
研究:逻辑结构、存储结构、数据运算
关系-------逻辑结构
逻辑结构是数据之间的抽象关系
四种逻辑结构:集合结构、线性结构、树形结构、图形结构
集合结构
所有数据元素之间没有任何关系,只不过这些数据元素有共同的属性、特点以及同属于一个整体
线性结构
数据元素之间存在先后顺序。最多1个前驱,一个后继
树形结构
数据元素之间是一种层次关系。一个前驱,n个后继
图形结构
数据元素之间存在多个关系。n个前驱、n个后继
存储--------存储结构
数据逻辑结构在计算机中的映射。就是在计算机中存储数据,并表示出这些数据之间关系
顺序存储---------连续内存空间
将数据元素存储在一段连续的空间中,也就是说这些数据在内存中的存储地址是连续的,只需要知道第一个数据元素的地址,就可以知道其他数据元素的地址。例如数组
将数据元素按照逻辑顺序存储在内存中一段连续的空间,利用内存空间的地址来表示先后顺序
链式存储------------数据的存储空间是随机的
数据元素在内存中的存储地址是随机的,不一定是连续的,(所以不需要一次性全部申请空间,根据需要来申请空间)需要通过在存储数据元素的同时,将下一个数据元素的地址一并存上。这样任然能够表示数据元素之间的关系。
链式存储 : 存储数据元素 + 关系
索引存储
在存储数据元素的同时,还要存储数据的索引在一个索引表中,可以通过索引表得到数据元素之间的关系。例如:电话簿
散列存储
通过数元素中的部分关键字,进行某种运算得到该数据元素的地址。
运算--------数据操作
增、删、该、查
算法
算法定义
算法就是解决某个问题的方法步骤
在计算机中算法是一个有限的语句集合
算法与程序的区别
算法就是解决某个问题的方法步骤,程序是在计算机中以计算机语言具体实现
区别:算法不一定要依赖计算机语言,是一种描述方式。程序是必须要依赖计算机语。算法是有限的,程序可以是无穷的。
算法与数据结构
算法设计:依赖于数据结构的逻辑结构
算法的实现:依赖于数据结构的存储结构
程序=数据结构+算法
算法的好坏判断
- 正确性
- 效率:消耗时间多少、消耗空间多少
- 编程:算法结构好、易于、理解、编写、调试
算法的效率度量
时间复杂度
时间计算:
-
事后统计法
把算法实现,进行运行,得到算法运行消耗的时间。
**缺陷:**依赖于特定的计算机软硬件,进行大量的统计
-
事先估计法
假设所有计算机执行一条指令的时间都是一致的,只需要统计出执行的语句的次数
语句频度:算法中一条语句的重复次数
时间复杂度T(n):所有语句频度之和就是算法的语句执行次数
在循环中一条语句,执行次数不确定,就用问题规模n来表示
通常利用事先估计法来表示算法时间。
计算时间复杂度
-
T(n)表示法:每条语句的语句频度 * 语句条数
-
大O表示法O(n):n代表无穷大,并且取T(n)表达式的最高次幂。如果语句执行次数为常数次,那么O(n)=1;
空间复杂度S(N)
占用空间的大小
一、线性表
线性表概念
多个数据元素的逻辑结构为线性关系,这些数据元素之间存在先后顺序,就叫做线性结构,即是线性表。数组就是一个
线性关系:中有且仅有“第一个数据元素”和一个“最后一个数据元素”,中间的数据元素只有一个前驱和一个后继
在存储线性表时,既需要存储具有线性表的数据元素,也需要存储元素数据之间的关系。
总而言之,线性表就是一种逻辑结构为线性结构关系的逻辑结构
线性表的存储结构
线性表的顺序存储:存储数据元素时,把数据元素按照逻辑关系(先后顺序),依次存储在一段连续的内存空间,借助元素在这段连续空间的地址,来表示数据间的先后顺序,这就是顺序结构
顺序表
顺序表 = 数据元素逻辑结构为线性表 + 存储结构为顺序存储。
数组就是一个顺序表
顺序表的运算
-
添加
-
删除
-
修改
-
查找
-
判断满
-
判断空
-
求表长
-
创建表
-
清空表
顺序表的实现
- 申请一段连续的内存空间来存储数据,通过地址来表示先后关系
- 记录表中元素的个数
顺序存储的缺陷
- 要申请一段连续的内存空间,申请的时候大小就已经固定了,空间不能动态的添加、删除,这样比较占用内存资源
- 插入、删除操作比较麻烦,需要移动整片空间
#include <stdio.h>
#include <stdlib.h>
struct array
{
int num;
//struct book Book[50]; //表示为申请了50个连续的空间,每个元素为book
int no[20]; //定义一个,int类型的数组来存储每一本书的编号
};
//在堆中动态创建结构体,并返回结构体在堆中的首地址
struct array * creat()
{
struct array * p=malloc(sizeof(struct array));
if(p==NULL)
{
printf("内存空间申请失败!\n");
return NULL;
}
p->num=0;
return p;
}
//判断结构体空间是否为空
int empty(struct array *p)
{
if(p->num == 0)
{
printf("空间为空\n");
return 1; //空间为空返回1
}
return 0;
}
//判断是否空间是否满了
int full(struct array *p)
{
if(p->num == 20)
{
printf("空间已满\n"); //空间如果满了返回1
return 1;
}
return 0; //空间如果没满返回0
}
//添加新的元素
void add(struct array * p,int pos,int shu) //传入结构体的首地址和需要添加元素的位置、添加的元素的值
{
//判断空间是否为满了
if(full(p))
{
return ; //如果空间满了,那就自接退出,不操作
}
//判断空间是否为空
if(empty(p)) //空间为空,那么就将插入的数据添加到no数组第0个元素位置
{
p->no[0]=shu;
p->num ++;
return ;
}
//判断插入下标是否越界
if(pos > p->num -1 )
{
printf("现在有%d个数据,下标范围是0~%d\n",p->num,(p->num) -1);
printf("插入的数据下标为%d超出下标范围,将该数据加在最后一个数据元素后面\n",pos);
putchar('\n');
p->no[p->num]=shu; //越界了要将数据添加在最后一个元素后面,而不是覆盖最后一个元素p->no[p->num-1]
p->num ++;
return ; //插入元素下标越界,结束添加功能
}
for(int i = p->num - 1;i >= pos ;i--) //将pos处以及之后的元素后一位,空出来给添加的元素
{
p->no[i+1]=p->no[i];
}
p->no[pos]=shu;
p->num ++;
}
//删除执行位置的数据元素
void del(struct array *p,int pos,int * k)
{
//判断是否为空
if(empty(p))
{
return ;
}
//判断下标是否越界
if(pos >= p->num -1)
{
printf("现在有%d个数据,下标范围是0~%d\n",p->num,(p->num) -1);
printf("删除的数据下标为%d超出下标范围,将k的值赋值为0\n",pos);
putchar('\n');
*k=0;
return ; //插入元素下标越界,结束添加功能
}
*k=p->no[pos];
printf("需要删除下标为%d,数据为%d\n",pos,*k);
for(int i=pos;i< p->num-1;i++) //将pos之后的第一个元素赋值给pos的位置,其他元素一次前移一个位置
{
//检验判断的条件是,将条件带入到式子中,最后一次前移是,p->nos[num-2]=p->nos[num-1];
p->no[i]=p->no[i+1];
}
printf("删除成功\n");
p->num --;
}
//查找数据元素
void reserch(struct array *p,int pos)
{
//判断查看的下标是否越界
if(pos > p->num -1)
{
printf("现在有%d个数据,下标范围是0~%d\n",p->num,(p->num) -1);
printf("查看的数据下标为%d超出下标范围,自接退出查找\n",pos);
putchar('\n');
return ; //插入元素下标越界,结束添加功能
}
printf("查看的数据元素是下标为%d的元素数据%d\n",pos,p->no[pos]);
}
//修改数据元素
void change(struct array *p,int pos,int shu)
{
//判断查看的下标是否越界
if(pos > p->num -1)
{
printf("现在有%d个数据,下标范围是0~%d\n",p->num,(p->num) -1);
printf("查看的数据下标为%d超出下标范围,自接退出修改\n",pos);
putchar('\n');
return ; //插入元素下标越界,结束添加功能
}
printf("修改前:%d\n",p->no[pos]);
p->no[pos]=shu;
printf("修改完成\n");
printf("修改后:%d\n",p->no[pos]);
}
//数据显示
void show(struct array *p)
{
for(int i=0;i<p->num;i++)
{
printf("%d ",p->no[i]);
}
putchar('\n');
}
int main()
{
int k=0;
struct array *p=creat();
show(p);
add(p,10,1);
add(p,10,2);
add(p,10,3);
add(p,10,4);
add(p,10,5);
add(p,10,6);
show(p);
del(p,0,&k);
show(p);
add(p,4,7);
show(p);
reserch(p,5);
change(p,0,8);