由于本周学习数据结构,下面是我一周的笔记:
①数据结构:是相互之间存在一种或多种特定关
系的数据元素的集合。
②按照试点的不同,把数据结构分为逻辑结构和物理结构:
(1)逻辑结构:是指数据对象中数据元素之间的相互关系
<1>集合结构:集合结构中的数据元素除了同属于一个集合外,它们之间没有其他关系。
<2>线性结构:线型结构中的数据元素之间是一对一的关系。
<3>树形结构:树形结构中数据元素之间存在一种一对多的层次关系。
<4>图形结构:图形结构的数据元素是多对多的关系
(2)物理结构:是指数据的逻辑结构在计算机中的存储形式。
<1>顺序存储结构:是把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。
<2>链式存储结构:是把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。
③抽象数据类型(ADT):是指一个数学模型,及定义在该模型上的一组操作。
ADT 抽象数据类型名
Data
数据原数之间逻辑关系的定义
Operation
操作1
初始条件
操作结果描述
操作2
......
操作n
......
endADT
④算法:
(1)算法的定义:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
(2)算法的特性:输入输出 有穷性 确定性 可行性
(3)算法设计的要求:正确性 可读性 健壮性 时间效率高和存储量低
需要注意的是:健壮性:当输入数据不合法时,算法也能做出相关处理,而不是产生异常或莫名奇妙的结果。
(4)算法时间复杂度:大O阶方法:
1,用常数1取代运行时间中的所有加法常数。
2.在修改后的运行次数函数中,只保留最高阶项。
3.如果最高阶项存在且不是1,则去除与这个项相乘的常数。
(5)常见的时间复杂度大小排序:
O(1)<O(logn)<O(n)<O(nlogn)<O(nn)<O(nn*n)<O(2的n次方)<O(n的阶乘)<O(n的n次方)
⑤线性表的抽象数据类型:
ADT 线性表(List)
Data
线性表的数据对象集合为{a1,a2,...,an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后驱元素。数据元素之间的关系是一对一的关系。
Operation
InitList(*L):初始化操作,建立一个空的线性表L。
ListEmpty(L):若线性表为空,返回ture,否则返回false。
ClearList(*L):将线性表清空。
GetElem(L,i,*e):将线性表L中的第i个位置元素值返回给e。
LocateElem(L,e):在线性表L中查找与给定值e相等的元素,如果找到,就返回该数元素在表中的位置序号;否则返回0表示失败。
ListInsert(*L,i,e):在线性表L中的第i个位置插入新元素e。
ListDelete:(*L,i,*e):删除线性表L中第i个元素,并用e返回其值。
ListLength(L):返回线性表L中的元素个数。
endADT
下面就用一个实例来展现这个这个抽象数据类型的使用方法:
例:要实现连个线性表集合A和B的并集操作。使得A=AUB。首先需要明白的是,这里只需要将存在集合B中但不存在集合A中的元素插入到集合A中即可。
所以,可以有如下操作
void unionL(List *La,List Lb)
{
int La_len,Lb_len,i;
ElemType e; //声明与La和Lb相同的元素e
La_len=ListLength(*La);
Lb_len=ListLength(Lb);//求线性表的长度
for(i=1;i<=Lb_len;i++)
{
GetElem(Lb,i,&e);//取Lb中第i个数据元素赋值给e
if(!LocatElem(*La,e))
{
ListInsert(La,++La_len,e);
}//如果La中不存在和e相等的数据元素,就插入到La中
}
}
通过这个,主要是可以对抽象数据结构有一个更深的理解。
⑥线性表的顺序存储结构:
来看线性表的顺序存储结构的结构代码:
#define MAXSIZE 20
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];
int length;
}SqList;
下面是在上面这个定义的基础上的对顺序存储结构的一些基本操作:
①
储结构的操作——获得元素操作
#define OK 1
#define ERROR 0
#define TURE 1
#define FALSE 0
typedef int Status;
//初始条件:顺序线性表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;>=i-1;k--)
{
L->data[k+1]=L->data[k];
}
}
L->data[i-1]=e;
L->length++;
return OK;
}
这里有需要值得注意的几点:
(1)
if(L->length==MAXSIZE)//顺序表已满
{
return ERROR;
}
这个判断表已满的方法,需要明白
(2)
if(i<1||i>L->length+1)//若i不在范围内
{
return ERROR;
}
这里是在对i 的正确性进行判断:
<1>已存在的线性表当中的节点是连续的从第1个,第2个…第L->length个;
<2>而现在要进行的是插入操作,并且注意到这里插入的结果都是插入到第i 个元素之前
<3>同时能够插入的位置除了中间的一般的位置,头部和尾部两个特殊位置还需注意,应该能够插入到第1个元素之前,使之成为新的第一个元素,也能够插入到第L->length+1个元素之前,使之成为新的尾部。
所以带入的i的值的不应该小于1,和大于L->length+1
(3)
<1>首先if判断语句,
if(i<=L->length)
i<=L->length表示插入的位置不是要插在表尾
<2>循环体:
for(k=L->length-1;>=i-1;k--)
{
L->data[k+1]=L->data[k];
}
首先需要知道它的作用结果是将要插入为之后的数据元素都向后移动一位
然而要准确理解的话,可以带入值:
①
k=L->length-1 时
L->data[L->length]=L->data[L->length-1];
②
第1个,第2个...第i个元素对应数组元素 下标0,1...i-1
k=i-1 时
L->data[i]=L->data[i-1];
(4)最后两句:
L->data[i-1]=e;
L->length++;
第一句就是在将新元素插在第i个位置;第二句就是在将线性表长度加一。
值得注意的是第一句由于是在上一个if语句之外,则它的作用就还包括了插入的位置是表尾的情况,如何实现的呢?带入即可:
i=L->length+1 时
L->data[L->length]=e;
3.删除操作
//删除操作
//初始条件:顺序线性表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)
{
return ERROR;
}
*e=L->data[i-1];
if(i<L->length)
{
for(k=i;k<L->length;k++)
{
L->data[-1]=L->data[k];
}
}
L->length--;
return OK;
}
解析:
①第一个判断
if(L->length==0)
{
return ERROR;
}
L->length==0表示线性表为空的情况,既然要删除,那线性表就不能什么都没有,不能是空的。注意这里可以与上面插入时的第一个判断比较,在插入时先排除的是表满的情况,因为这里的线性表是用数组实现的,它的长度是有限度的。表如果满了的话,就不能再插入了。
②第二个判断:
if(i<1||i>L->length)
{
return ERROR;
}
既然是要删除,就只能在一已有的元素上进行操作,元素的范围就只能是第1个~第L->length个。
③在删除之前将第i个元素的值取出并存入e中。
④第三个判断,
if(i<L->length)
...
使得ilength的原因是,最后一个元素的删除操作是通过直接将长度减1实现的不需要一动其它元素。
⑤循环:
for(k=i;k<L->length;k++)
{
L->data[k-1]=L->data[k];
}
理解:
(1)
k=i 时
L->data[i-1]=L->data[i];
(2)
k=L->length-1 时
L->data[i-2]=L->data[L->length-1];
实际就是将删除位置后继元素前移。
⑥最后将长度减1
L->length--;
注意对应上面所说的当i=L->length时,最后一个元素的删除操作是通过直接将长度减1实现的不需要一动其它元素。