逻辑结构
集合结构、线性结构、树形结构、图形结构;
物理结构
顺序存储结构、链式存储结构;
算法的特性
输入:算法具有0个或多个输入,对绝大多数算法而言输入参数都是必要的;
输出:算法至少有1个或多个输出,算法一定有输出;
有穷性:算法在执行有限的步骤之后,自动结束而不会出现无限循环,并且每一个步骤在可接受的时间内完成;
确定性:算法的每一个步骤都有明确的含义,不会出现二义性;算法在一定条件下,只有一条执行路径,相同的输入只能有唯一的输出结果;
可行性:算法的每一步都能够通过执行有限的次数完成;
算法设计的要求
正确性、可读性、健壮性、时间效率高和存储量低;
时间复杂度和空间复杂度
算法效率的度量方法:
事后统计方法、事前分析估算方法;
结论:判断一个算法的效率时,函数中的常数和其他次要项常常可以忽略,而更应该关注主项(最高项)的阶数;
常数阶O(1)、线性阶O(n)、平方阶O(n^2)、对数阶O(logn)【2^x=n 》 x=log(2)n】
函数调用的时间复杂度分析:
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n);
最坏情况和平均情况;
算法的空间复杂度:
线性表(List)
定义:由0个或多个数据元素组成的有限序列。
数据类型:是指一组性质相同的值的集合及定义在此集合上的一些操作的总称。
——原子类型:不可再分解的基本类型,例如整型、浮点型、字符型;
——结构类型:由若干个类型组合而成,是可以在分解的,例如整型数组是由若干整型数据组成的;
抽象数据类型(Abstract Data Type,ADT)是指一个数学模型及定义在该模型上的一组操作。抽象数据类型的定义仅取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关。
ADT List
Data
{a1,a2,...,an}
Operation
//La表示A集合,Lb表示B集合。
void unionL(List *La,List Lb)
{
int La_len,Lb_len,i;
ElemType e;
La_len = ListLength(*La)
Lb_len = ListLength(Lb)
for(i=1;i<=Lb_len;i++)
{
GetElem(Lb,i,&e);
if(!LocateElem(*La,e))
{
ListInsert(La,++La_len,e);
}
}
}
线性表的顺序存储结构和链式存储结构
#define MAXSIZE 20
typedef int ELemType;
typedef struct
{
ElemType data[MAXSIZE]
int length; //线性表当前长度
} SqList;
对数组进行封装,增加了当前长度的变量。
——存储空间的起始位置,数组data,它的存储位置就是线性表存储空间的存储位置;
——线性表的最大存储容量:数组的长度MaxSize;
——线性表的当前长度:length。
地址计算方法:LOC(ai)=LOC(a1)+(i-1)*c
//getElem.c
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
//Status是函数的类型,其值是函数结果状态代码,如OK等;
//初识条件:顺序线性表L已存在,1<=i<=ListLength(L)
//操作结果:是用e返回L中第i个数据元素的值
Status GetElem(SqList L,int i,ElemType *e)
{
if(L.length==0||i<1||i>L.length)
{
return ERROR;
}
*e=L.data[i-1];
return OK;
}
/*初始条件:顺序线性表L已存在,1<=i<=Listlength(L)*/
/*操作结果:在L中第i个位置之前插入新的数据元素e,L的长度+1*/
Status ListInsert(SqList *L,int i,ElemType e)
{
int k;
if(L->length==MAXSIZE) //顺序线性表已经满了
{
return ERROR;
}
if(i<1||i>L->length+1) //当i不在范围内时
{
return ERROR;
}
if(i<=L->length) //若插入数据位置不在表尾
{
/*将要插入位置后数据元素向后移动一位*/
for(k=L->length-1;k>=i-1;k--)
{
L->data[k+1]=L->data[k];
}
}
L->data[i-1]=e; //将新元素插入
L->length++;
return OK;
}
/*初始条件:顺序线性表L已存在,1<=i<=Listlength(L)*/
/*操作结果:删除L的第i个元素,并用e返回其值,L的长度-1*/
Status ListDelete(SqList *L,int i,ElemType e)
{
int k;
if(L->length==0) //顺序线性表为空
{
return ERROR;
}
if(i<1||i>L->length) //当i不在范围内时
{
return ERROR;
}
*e = L->data[i-1];
if(i < L->length) //若删除数据位置不在表尾
{
/*将要删除位置后数据元素向前移动一位*/
for(k=i;k<L->length;;k++)
{
L->data[k-1]=L->data[k];
}
}
L->length--;
return OK;
}
时间复杂度:
最好情况O(1)
最坏情况O(n)
平均情况[O(1)+O(n)]/2
头指针与头结点的异同
结构指针描述单链表
typedef struct Node
{
ElemType data; //数据域
struct Node* Next; //指针域
} Node;
typedef struct Node* LinkList;
/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e返回L中第i个数据元素的值*/
Status GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList P;
P = L->next;
j = 1;
while(P && j<i)
{
P = P->next;
++j;
}
if(!P || j>i)
{
return ERROR;
}
*e = P->data;
return OK;
}
单链表的插入
/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:在L中的第i个位置之前插入新的数据元素e,L的长度加1*/
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p=*L;
j=1;
while(p&&j<i) //用于寻找第i个结点
{
p=p->next;
j++;
}
if(!p || j>i)
{
return ERROR;
}
s=(LinkList)malloc(sizeof(Node));
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:删除L中的第i个数据元素,并用e返回其值,L的长度-1*/
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,q;
p=*L;
j=1;
while(p->next && j<i) //用于寻找第i个结点
{
p=p->next;
j++;
}
if(!(p->next) || j>i)
{
return ERROR;
}
q=p->next;
p->next=q->next;
*e=q->data;
free(q);
return OK;
}
头插法建立单链表
/*头插法建立单链表示例*/
void CreateListHead(LinkList *L,int n)
{
LinkList p;
int i;
srand(time(0)); //初始化随机数种子
(*L)->next=NULL;
for(i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node)); //生成新结点
p->data=rand()%100+1;
p->next=(*L)->next;
(*L)->next=p;
}
}
尾插法建立单链表
/*尾插法建立单链表示例*/
void CreateListTail(LinkList *L,int n)
{
LinkList p,r;
int i;
srand(time(0)); //初始化随机数种子
*L = (LinkList)malloc(sizeof(Node));
r=*L;
for(i=0;i<n;i++)
{
p=(Node *)malloc(sizeof(Node)); //生成新结点
p->data=rand()%100+1;
r->next=p;
r=p;
}
r->next=NULL;
}