一、顺序印象&非顺序印象
是数据元素之间的关系在计算机中有两种不同的表示方法
二、顺序存储结构&链式存储结构
由两种印象得到两种不同的存储结构
1、顺序存储结构特点(连续)
借助元素在存储器中的相对位置来表示数据元素之间的逻辑关系
方便查找,增删数据麻烦
没有结点概念,只有元素
2、链式存储结构特点(不连续)
借助指示元素存储地址的指针表示数据元素之间的逻辑关系
方便增删数据,查找麻烦(得从头开始查找)
链式的插入不能先断之前的指针,否则会找不到后面的结点
结点含数据域和指针域
三、抽象数据类型(ADT)
ADT 抽象数据类型名{
数据对象:<数据对象的定义>;
数据关系:<数据关系的定义>;
基本操作:<基本操作的定义>;
}ADT 抽象数据类型名
其中数据对象和数据关系的定义用伪码描述,基本操作的定义格式为
基本操作(参数表)
初始条件:<初始条件描述>
操作结果:<操作结果描述>
基本操作有两种操作:
1.赋值操作只为操作提供输入值
2.引用参数以&打头,除可提供输入值外还将返回操作结果
“初始条件”
描述了操作执行之前数据结构和参数应满足的条件,若不满足,则操作失败,并返回相应出错信息。
“操作结果”
说明了操作正常完成之后,数据结构的变化状况和应返回的结果,若初始条件为空,则省略之
四、抽象数据类型例子
抽象数据类型三元组定义
ADT Triplet{
数据对象:D={e1,e2,e3|e1,e2,e3属于ElemSet(定义了关系运算的某个集合)}
数据关系:R1={<e1,e2>,<e2,e3>}
基本操作:
InitTriplet(&T,v1,v2,v3)
//操作结果:构造了三元组T,元素e1,e2和e3分别被赋以参数v1,v2和v3的值
DestroyTriplet(&T)
//操作结果:三元组T被销毁
Get(T,i,&e)
//初始条件:三元组T已存在,1<=i<=3
//操作结果:用e返回T的第i元的值
Put(&T,i,e)
//初始条件:三元组T已存在,1<=i<=3
//操作结果:改变T的第i元的值为e
IsAscending(T)
//初始条件:三元组T已存在
//操作结果:如果T的3个元素按升序排列,则返回1,否则返回0
IsDescending(T)
//初始条件:三元组T已存在
//操作结果:如果T的3个元素按降序排列,则返回1,否则返回0
Max(T,&e)
//初始条件:三元组T已存在
//操作结果:用e返回T的3个元素的最大值
Min(T,&e)
//初始条件:三元组T已存在
//操作结果:用e返回T的3个元素的最小值
}
五、因为&为引用时是在C++中,在C中是取地址的意思,如果想写成纯C的两种办法
1.原例(直接在纯C下是无法实现的,必须要C和C++混用,强烈不推荐)
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
typedef struct{
float realpart;//实部
float imagpart;//虚部
}complex;
void Assign(complex &z,float r,float i)
{
z.realpart=r;
z.imagpart=i;
}
int main()
{
complex m;
Assign(m,1.1,2.2);
printf("%f",m.realpart);
return 0;
}
2、纯C方法一(将&引用取消)
#include <stdio.h>
typedef struct{
float realpart;//实部
float imagpart;//虚部
}complex;
complex Assign(complex z,float r,float i)
{
z.realpart=r;
z.imagpart=i;
return z;
}
int main()
{
complex m;
complex C;
C=Assign(m,1.1,2.2);
printf("%f",C.realpart);
return 0;
}
3、纯C方法二(将&引用改为指针符号*)
#include<stdio.h>
typedef struct {
float realpart;
float imagpart;
}complex;
void Assign(complex *z, float r, float i)
{
z->realpart = r;
z->imagpart = i;
}
int main()
{
complex *m = (complex *)malloc(sizeof(complex));
Assign(m, 1.1, 2.2);
printf("%f %f", m->realpart, m->imagpart);
free(m);
return 0;
}
六、算法五大特性
1.有穷性
一个算法必须总是(对任何合法的输入值)在执行有穷步之后结束,且每一步都可在有穷时间内完成
2.确定性
算法中每一条指令都要求确切的含义,且算法只有唯一的一条执行路径,即对于相同的输入只能得出相同的结果
3.可行性
算法是可行的
4.输入
5.输出
七、设计算法原则
1.正确性
2.可读性
3.健壮性
4.效率与低存储量需求
效率指算法执行时间,存储量需求指算法执行过程中所需要的最大存储量
八、时间复杂度
简单的说时间复杂度就是计算算法中基本操作重复执行的次数记为O(f(n)),基本操作是指最深层循环的语句的原操作
频度
指最深层循环的语句重复执行的次数
例子
1.常量阶,时间复杂度为O(1)
{++x;s=0}
2.线性阶,时间复杂度为O(n)
for(i=1;i<=n;i++){++x;s+=x}
3.平方阶,时间复杂度为O(n^2)
for(j=1;j<=n;j++)
for(k=1;k<=n;K++)
{++x;s+=x;}
4.对数阶,时间复杂度为O(logn)
最常见的是二分查找
#include<stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
int right=5;
int left=0;
int mid;
while(left<=right)
{
mid=(left+right)/2;
if(a[mid]<1)
{
left=mid;
}
else if(a[mid]>1)
{
right=mid;
}
else{
printf("%d",mid);
break;
}
}
}
5.有时候算法的基本操作重复执行次数还随问题的输入数据集不同而不同
比如冒泡排序,输入数据有序而无序,其结果是不一样的
或是以下例子,数组数据和n都会影响
void bubble_sort(int a[],int n)
{
for(i=n-1,change=TURE;i>1&&change;–i)
{
change=false;
for(j=0;j
九、平均时间复杂度
平均时间复杂度就是计算出该算法最深层循环的原语句重复执行次数的方程后取最高次的(即取最坏的结果,其他的都可忽略(包括比如1/2*n^2,只要取n^2就好))
例
for(int i=2;i<=n;i++)
for(j=2;j<=i-1;++j)
{++x;a[i][j]=x;}
计算最深层循环的原语句操作次数
当i=2–》0次,i=3–》1次,i=4–》2次…..i=n–》n-2次
所以次数即1+2+3+…n-2,为1/2(n^2-3n+2),所以平均时间复杂度取O(n^2)
十、时间复杂度比较
多项式级
O(1)< O(logn)< O(n)< O(nlogn)< O(n^2)< O(n^3)
指数级
O(2^n)< O(n!)< O(n^n)