知识点
1 绪论
1.1 数据结构的基本概念
1.1.1 基本概念和术语
数据:信息的载体
数据元素:数据的基本单位(整体考虑),由若干数据项(不可分割)组成。组合项:年月日等。
数据对象:具有相同性质的元素的集合,是数据的子集(性质相同:账号的集合)
数据结构:互相存在一种或多种特定关系的元素的集合(存在关系:财富排行榜)
数据类型
1.1.2 数据结构的三要素
逻辑结构独立于存储结构,存储结构依赖于逻辑结构
逻辑结构:集合、线性结构(一对一)、树形结构(一对多)、图状结构或网状结构(多对多)
存储结构
描述 | 优点 | 缺点 | |
---|---|---|---|
顺序存储 | 逻辑相邻物理也相邻 | 随机存取 每个元素占用最少的空间 |
产生外部碎片 |
链式存储 | 不要求逻辑上相邻即物理相邻 | 不会产生碎片,充分利用存储空间 | 指针占用额外空间 只能顺序存取 |
索引存储 | 建立索引表(索引项) | 检索速度快 | 索引表额外占用空间 修改索引表耗时 |
散列存储 | 根据关键字直接算出地址,又称哈希存储 | 检索、增加、删除节点都很快 | 散列函数不好时增加开销 |
运算
运算的__定义__是针对逻辑结构的,运算的实现是针对存储结构的。
1.2 算法和算法评价
1.2.1 算法的基本概念
算法是对特定问题求解步骤的描述,是指令的有限序列。
算法(有穷) <> 程序(无穷,微信可以一直运行)
程序 = 算法 + 数据结构 (算法独立于数据结构)
软件 = 程序 + 数据 + 文档
算法的特性:有穷性、确定性、可行性、输入、输出。
好的算法:正确性、可读性、健壮性、效率与低存储量需求
1.2.2 算法效率的度量
时间复杂度
空间复杂度
第二章 线性表
顺序表
SqList
//顺序表静态分配
#define MAxSize 50
typedef struct{
ElemType data[MaxSize];
int length;
}SqList;
void InitList(SqList &L)
//顺序表静态分配的初始化
void InitList(SqList &L){
L.length=0;
}
SeqList
void InitList(SeqList &L)
void IncreaseSize(SeqList &L,int len)
//顺序表动态分配
#define InitSize 50
typedef struct{
ElemType *data;
int MaxSize,length;
}SeqList;
//顺序表动态分配的初始化
#define InitSize 10
void InitList(SeqList &L){
L.data=(ElemType*)malloc(InitSize*sizeof(ElemType));
L.length=0;
L.MaxSize=InitSize;
}
//扩展动态数组
void IncreaseSize(SeqList &L,int len){
int *p=L.data;//保存原指针
L.data=(ElemType*)malloc((L.MaxSize + len) * sizeof(ElemType));
for(int i=0; i<L.length; i++)//循环复制
L.data[i] = p[i];
L.MaxSize += len; //Size变大但len不变
free(p); //释放
}
int main(){
SeqList L;//定义
InitList(L);//初始化
//..添加...
IncreaseSize(L, 5);//扩展
return 0;
}
bool ListInsert(SqList &L,int i,ElemType e)
//在位序为i的位置插入元素e
bool ListInsert(SqList &L,int i,ElemType e){
if(i<1 || i>L.length + 1) //判断位序合法
return false;// i可以等于length+1(插在末尾)
if(L.length>=MaxSize) //判断空间没满
return false;
for(int j = L.length; j>=i; j--)
L.data[j] = L.data[j-1]; //移动元素
L.data[i-1] = e;
L.length++; //长度++
return true;
}
bool ListDelete(SqList &L,int i,ElemType &e)
//删除位序为i的元素,赋值给e
bool ListDelete(SqList &L,int i,ElemType &e){
if(i<1 || i>L.length) //判断位序合法
return false;
e = L.data[i-1]; //赋值
for(int j=i; j<L.length; j++) //移动
L.data[j-1] = L.data[j];
L.length--;
//长度--
return true;
}
int LocateElem(SqList L,ElemType e)
//按值查找,返回位序
int LocateElem(SqList L,ElemType e){
int i;
for(i=0; i<L.length; i++)
if(L.data[i] == e)return i+1;
return 0;
}
ElemType GetElem(SqList L,int i)
ElemType GetElem(SqList L,int i){
//按位查找,返回值
if(i<1 || i>L.length)return false; //判断合法
return L.data[i-1];
}
单链表(带头结点)
LNode,*LinkList
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
bool InitList(LinkList &L)
//不带头结点
bool InitList(LinkList &L){
L=NULL;
return true;
}
//带头结点:
bool InitList(LinkList &L){
//头结点不需要在main函数中分配
L=(LNode*)malloc(sizeof(LNode)); //头结点
if(L==NULL)return false; //分配失败
L->next=NULL;
return true;
}
bool Empty(LinkList L)
bool Empty(LinkList L){
return (L==NULL);//不带头结点
return (L->next==NULL);//带头结点
}
LinkList List_HeadInsert(LinkList &L)
//头插法
LinkList List_HeadInsert(LinkList &L){
LNode *s;
int x;
L=(LinkList)malloc(sizeof(LNode)); //头结点
L->next=NULL;//头指针
scanf("%d", &x);
while(x!=9999){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d", &x);
}
return L;
}
LinkList List_TailInsert(LinkList &L)
//带头结点
LinkList List_TailInsert(LinkList &L){
int x;
L=(LinkList)malloc(sizeof(LNode));
LNode *s, *r=L;//尾指针
scanf("%d",&x);
while(x!=9999){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;//置尾指针
return L;
}
LNode *GetElem(LinkList L,int i)
//返回位序为i的节点的指针
LNode *GetElem(LinkList L,int i){
int j = 1;
LNode *p = L->next;
//若为头结点,直接返回L
if(i==0)return L;
//小于0,不合法,返回NULL
if(i<1)return NULL;
//计数同时判非空,返回
while(p!=NULL && j<i){
p = p->next;
j++;
}
return p;
}
LNode *LocateElem(LinkList L,ElemType e)
LNode *LocateElem(LinkList L,ElemType e){
//判值同时判非空
}
bool ListInsert(LinkList &L,int i,ElemType e)
//按位序插入(调用)
bool ListInsert(LinkList &L,int i,ElemType e){
//在位序i处插入e
if(i<1)return false;
LNode *p = GetElem(L,i-1);//找到前一个结点(若在不带头结点的链表的首部插入,需单独讨论)
return InsertNextNode(p,e);//后插
}
//按位序插入(带头结点)
bool ListInsert(LinkList &L, int i, ElemType e){
if(i<1)return false;//最小插入位置为1(位序)
LNode *p;
int j = 0;//第几个节点
p = L;//遍历
while(p!=NULL && j<i-1){
//位序为i,则下标为i-1
p = p->next;
j++;
}
if(p==NULL)return false;//退出循环的原因是链表到头了
LNode *s = (LNode*)malloc(sizeof(LNode)); //新节点
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//按位序插入(不带头结点)
bool ListInsert(LinkList &L, int i, ElemType e){
if(i<1)return false;
if(i==1){
//在首部插入单独考虑(操作不同)
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = L; //这两行操作不同
L = s; //这两行操作不同
return true;
}
LNode *p;
int j = 1;//最开始就是第一个节点
p = L;
while(p!=NULL && j<i-1){
p = p->next;
j++;
}
if(p==NULL)return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
bool ListDelete(LinkList &L,int i,ElemType &e)
//删除位序i(带头结点)
bool ListDelete(LinkList &L,int i,ElemType &e){
if(i<1)return false;
LNode *p;
int j = 0;
p = L;
while(p!=NULL && j<i-1){
p = p->next;
j++;
}
if(p==NULL)return false;//i非法
LNode *q=p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}
//指定节点的删除(赋值后删后节点)
bool DeleteNode(LNode *p){
if(p==NULL)return false;
LNode *q = p->next;
p->data = p->next->data;//************************p->next可能为空(p为尾结点)*******
p->next = q->next;
free(q);
return true;
}
bool InsertNextNode(LNode *p,ElemType e)
bool InsertPriorNode(LNode *p,ElemType e)
bool InsertNextNode(LNode *p,ElemType e){
if(p==NULL)return false;
LNode *s = (LNode*)