1简介
1.1说明
意义:
数据结构指的是数据与数据之间的逻辑关系
作用:
解决问题,如何高效(多快好省)的从已知数据求解未知数据。
分类:
1.2算法
意义:
算法指的是解决特定问题的步骤和方法。
作用:
解决问题,如何高效(多快好省)的从已知数据求解未知数据。
1.3算法好坏的判断依据
对于一个问题的算法来说,之所以称之为算法,首先它必须能够解决这个问题(称为准确性)。其次,通过这个算法编写的程序要求在任何情况下不能崩溃(称为健壮性)。如果准确性和健壮性都满足,接下来,就要考虑最重要的一点:通过算法编写的程序,运行的效率怎么样。运行效率体现在两方面:
1:时间复杂度: 算法的运行时间;
2:空间复杂度: 运行算法所需的内存空间大小;
1.4时间复杂度
1.4.1意义:
算法的运行时间受硬件、系统等多个因素影响。我们使用一个与环境无关的方式评价算法执行速度:时间复杂度。
时间复杂度主要度量基本操作重复执行的次数,是输入规模和基本操作的数量关联,随着输入规模扩大的增长量。??
1.4.2表示时间复杂度的方法:
以下表示中时间复杂度有低到高
No. | 表示 | 级别 | 语句 |
---|---|---|---|
1 | O(1) | 常数(Constant) | 顺序语句、分支语句 |
2 | O(log_2n) | 对数(Logarithmic) | 递归 |
3 | O(n) | 线性(Linear) | 递归 |
4 | O(nlog_2n) | 线性对数(Linear Logarithmic) | 递归 |
5 | O(n^2) | 平方(2 Square) | 循环语句 |
6 | O(n^3) | 立方(3 Square) | 循环语句 |
7 | O(2^n) | 指数(Exponential) | 递归 |
8 | O(n!) | 阶乘(Factorial) | 递归 |
9 | O(n^n) | n次方(n Square) | 递归 |
1.4.3计算时间复杂度的方法
1: 找出基本语句(执行次数最多的语句)最内层循环的循环体
2: 计算基本语句的执行次数的数量级只保留最高次幂,忽略低次幂和最高次幂的系数
3: 用大O记号表示算法的时间性能
O(log_2n)
int n;
scanf("%d",&n);
int count = 0;
for(int i=0;i<n;i*=2){
printf("%d\n",++count);
}
1.5空间复杂度
1.5.1意义:
空间复杂度是指运行完一个程序所需内存的大小。
1.4.2表示空间复杂度的方法:
一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间 所以程序执行时所需存储空间包括以下两部分:
1:固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。 主要包括指令空间(即代码空间)、数据空间(常量、简单变量)
等所占的空间。这部分属于静态空间。
2:可变空间。这部分空间的主要包括动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法有关。
1.6线性结构
1.6.1意义:
线性结构,又称线性表。逻辑结构上数据元素之间存在一个对一个的相邻关系。线性结构是n个数据元素的有序(次序)集合
1.6.2特征
1.集合中必存在唯一的一个"第一个元素";
2.集合中必存在唯一的一个"最后的元素";
3.除最后元素之外,其它数据元素均有唯一的"后继";
4.除第一元素之外,其它数据元素均有唯一的"前驱"。
2顺序表
顺序表是用一组地址连续的存储单元依次存储线性表中的各个元素,使线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中
数组的缺点:大小(元素个数)不能改变,不能适用元素个数变化的情况。
数组可以看作无法改变大小的顺序表。
2.1用法和定义结构
用法 :顺序表通过一个结构体和结构体对应的接口使用。
定义结构体
typedef int SeqType; //存储单元类型
typedef struct{
SeqType *elem; //存储空间基地址
int size; //当前长度
} List;
或者
typedef struct list
{
int arr[100];
int len;//管理当前存放数据的个数
int size;//用于管理动态数组的大小
}LIST;
定义操作(接口)
#include<stdio.h>
typedef int ElemType;
typedef 5 N;
typedef struct{
ElemType elem[N]
int length;
}SeqList;
void init_SeqList(SeqList *L){
L->length=0;
}//顺序表初始化
int Insret_SeqList(SeqList *L,int i,ElemType x){
if(L->length==N-1){
printf("fill");
return 0;
}
if(i>L->length-1||i<1){
printf("set error");
return 0;
}
int j
for(j=L->length;j>=i;j--){
L->elem[j+1]=L->elem[j];
}
L->elem[i]=x;
L->length++;
return 1;
}//顺序表的插入
int Delete_SeqList(SeqList *L,int i){
int j;
if(i<1||i>L->length)
printf("不存在这个元素");
for(j=i;j<=L->length-1;j++){
L->elem[j]=L->elem[j+1];
}
L->length--;
return 1;
}//顺序表的删除
int Location_SeqList(SeqList *L,ElemType x){
int i=0;
for(i=0;i<L->length;i++){
if(L->elem[i]==x){
return i
}
}
if(i>L->length)
return 0;
}
4:获取元素个数
int sqlist_size(SqList* plist);
5:销毁顺序表
bool sqlist_destroy(SqList* plist);
2.2优化
1:容量:每次增加一个元素,都要重复释放申请内存。可以预先申请一部分备用。
int capacity; //当前分配的存储容量
每次预先申请多少?
2:创建:用户使用SeqType忘记初始化,可以把结构体定义和初始化合二为一。
SeqType sqlist_create(int size);
3:随机访问元素
获取元素sqlist_get(),只能获取到顺序表中的元素的副本,如果需要改变顺序表中的元素,可以提供如下函数。
SeqType* sqlist_at(SqList* plist,int index);
4:遍历
提供一个对顺序表的整体操作的接口。
typedef void (*SqList_Traversal)(const SeqType* value);
void sqlist_traverse(SqList* plist,SqList_Traversal fp);