个人用数据结构重点(待补充)

一、绪论

基本概念

数据:信息载体,可以被计算机识别与处理二进制0与1
数据元素:数据基本单位,由若干数据项组成
数据结构:存在一种或多种特定关系数据元素的集合
数据对象:拥有相同性质的数据元素的集合,是数据的一个子集
数据类型:值的集合,定义在此集合上的一组操作的总称
原子类型&结构类型
抽象数据类型:通常就是数据结构

三要素

逻辑结构

集合(各元素同属一个集合,无其他关系)
线性结构(元素之间是一对一的关系,有前驱与后继(头只有后继,尾只有前驱))
树形结构:(元素是一对多的关系)
图形结构:(元素是多对多的关系)

存储结构

顺序存储(存放到相邻的存储单元中)
链式存储(可以不相邻,用指针表示彼此之间的逻辑关系)
索引存储(建立索引表)
散列存储(哈希,利用关键字直接计算出地址)

数据运算

算法(处理数据结构中的信息来解决实际问题)

五特性

  1. 有穷性
  2. 确定性
  3. 可行性
  4. 输入(零个或多个
  5. 输出(一个或多个

“好”算法的特性

  1. 正确性
  2. 可读性
  3. 健壮性
  4. 高效率(时间复杂度)&低存储量(空间复杂度

算法的效率度量

时间复杂度计算

只考虑阶数最高的部分!
加法取最大阶,乘法保留最大阶
eg: n 3 + 2 n 2 = O ( n 3 ) n^3+2n^2=O(n^3) n3+2n2=O(n3)
O ( 1 ) < O ( l o g 2 n ) < O ( n ) < O ( n l o g 2 n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)<O(log_2n)<O(n)<O(nlog_2n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n) O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
实在无法比较复杂度时可以写 l i m n → ∞ f ( x ) g ( x ) lim_{n\to \infty}\frac{f(x)}{g(x)} limng(x)f(x),洛必达即可。
要会计算最坏复杂度最好复杂度平均复杂度(期望)

空间复杂度计算

只考虑阶数最高的部分!
可以是递归调用深度*每层需要空间

二、线性表(相同数据类型的有限序列)

L = ( a 1 , a 2 , . . . , a i , a i + 1 , . . . a n ) L=(a_1,a_2,...,a_i,a_{i+1},...a_n) L=(a1,a2,...,ai,ai+1,...an)
线性表位序从1开始!不是0开始!
表长难以估计,需要经常删除/增加元素->链表
表长可预估,查询搜索功能较多->顺序表

顺序表(顺序存储)

根据下标查找 O ( 1 ) O(1) O(1)
拓展容量不方便 O ( n ) O(n) O(n)
插入删除不方便,需要移动大量元素 O ( n ) O(n) O(n)

基本操作

  1. 初始化
  2. 销毁
  3. 插入
  4. 删除
  5. 按值查找
  6. 按位查找
  7. 求表长
  8. 输出表
  9. 判断为空

操作封装为函数
传入时使用"&"->需要把处理的结果“带回来”
sizeof(变量类型/结构体名):某类型所占类型(单位:字节
eg:sizeof(int)=4
如果不初始化,会出现**“脏数据”**(类似乱码的随机数据

具体实现

静态分配(需要初始化)
#define MaxSize 10
typedef struct{
	ElemType data[maxSize];
	int length;
}SeqList;

void InitList(SeqList &L){//初始化
	L.length=0;
}

bool ListInsert(SeqList &L,int index,int value){//插入元素O(n)
	if(i<1 || i>L.length+1)//下标越界
		return false;
	if(L.length>=MaxSize)//空间已满
		return false;
	for(int j=L.length;j>=index;j--){//将第index个后面的元素后移
		L.data[j]=L.data[j-1];
	}
	L.data[idex-1]=value;
	L.length++;//更新长度
	return true;
}

bool ListDelete(SeqList &L,int index,int &value){//删除元素O(n)
	if(i<1 || i>L.length) //下标越界
		return false;
	value=L.data[index-1];
	for(int j=index;j<L.length;j++){//将第index个后面的元素后移
		L.data[j-1]=L.data[j];
	}
	L.length--;//更新长度
	return true;
}

ElemType getElemByIndex(SeqList L ,int index){
	return L.data[index-1];
}

int getIndexByElem(SeqList L,ElemType e){
	for(int i=0;i<L.length;i++){
		if(L.data[i]==e)
			return i+1;
	}
	return 0;
}
动态分配(需要分配空间)
#define InitSize 10
typedef struct{
	ElemType *data;
	int maxSize;
	int length;
}SeqList;

void InitList(SeqList &L){//初始化
	SeqList.data=(ElemType *)malloc(sizeof(ElemType)*InitSize);//分配空间
	L.length=0;
	L.maxSize=InitSize;
}
/*
	如果需要增加动态数组的长度,需要:
	1. 先用一个指针p暂存原数据
	2. 用malloc重新分配
	3. 循环,将数据覆盖
	4. 更新maxSize
	5. free(p) 
*/
void IncreaseSize(SeqList &L,int len){
	ElemType *p=L.data;
	L.data=SeqList.data=(ElemType *)malloc(sizeof(ElemType)*(len+L.maxSize));//重分配区间
	for(int i=0;i<L.length;i++){
		L.data[i]=p[i];//数据覆盖
	}
	L.maxSize+=len;//更新最大长度
	free(p);//释放内存
}

链表(链式存储)

单链表

改变容量方便,但不能随机存取,要耗费一定资源来存放指针
带头结点的会多出一个NULL节点!
常用带头结点的写法!但实际考试可能都有!
无法逆向查找!

typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode,*LinkList;//分别是单节点和单链表

bool InitList(LinkList &L){//不带头结点的单链表创建
	L=NULL;
	return true;
}

bool Empty(LinkList L){//判断是否为空(不带头结点)
	return L==NULL;
}

bool InitList(LinkList &L){
	L=(LNode *)malloc(sizeof(LNode));
	if(L==NULL)
		return false;
	L->next=NULL;
	return true;
}

bool Empty(LinkList L){//判断是否为空(带头结点)
	return L->next==NULL;
}

LinkList List_HeadInsert(LinkList &L){//头插法建立单链表
	LNode *temp,ElemType x;
	L=(LinkList)malloc(sizeof(LNode));
	L->next=NULL;
	while(~输入x && x!=某个特殊终止符){
		temp=(LNode*)malloc(sizeof(LNode));
		temp->data=x;
		temp->next=L->next;
		L->next=temp;
	}
	return L;
}

LinkList List_TailInsert(LinkList &L){//尾插法建立单链表
	ElemType x;
	L=(LinkList)malloc(sizeof(LNode));
	LNode *temp,*r=L;
	while(~输入x && x!=某个特殊终止符){
		temp=(LNode*)malloc(sizeof(LNode));
		temp->data=x;
		r->next=temp;
		r=temp;
	}
	r->next=NULL;
	return L;
}

LNode * getElemByIndex(LinkList L,int index){
	if(i<0)
		return NULL;
	int pos=0;
	LNode *p=L;
	while(p!=NULL && pos<index){
		p=p->next;
		pos++;
	}
	return p;
}

int getLength(LinkList L){
	int len=0;
	LNode *p=L;
	while(p->next!=NULL){
		p=p->next;
		len++;
	}
	return len;
}

LNode * getElemByElem(LinkList L,ElemType value){//找到第一个数据为value的节点
	LNode *p=L->next;
	while(p!=NULL && p->data!=value){
		p-p>next;
	}
	return p;
}

bool ListInsert(LinkList &L,int index,ElemType value){//插入节点(带头结点)
	if(index<1)
		return false;
	LNode *p;
	int pos=0;
	p=L;
	while(p!=NULL && pos<index-1){//遍历到第i-1个
		p=p->next;
		pos++;
	}
	if(p==NULL)
		return false;//非法
	LNode *temp=(LNode *)malloc(sizeof(LNode));
	temp->data=value;
	temp->next=p->next;
	p->next=temp;
	return true;
}

bool ListInsert(LinkList &L,int index,ElemType value){//插入节点(不带头结点)
	if(i<1)
		return false;
	if(i==1){//比较特殊的位置
		LNode *temp=(LNode *)malloc(sizeof(LNode));
		temp->data=value;
		temp->next=L;
		L=temp;
		return true;
	}
	LNode *p;
	int pos=0;
	p=L;
	while(p!=NULL && pos<index-1){//遍历到第i-1个
		p=p->next;
		pos++;
	}
	if(p==NULL)
		return false;//非法
	LNode *temp=(LNode *)malloc(sizeof(LNode));
	temp->data=value;
	temp->next=p->next;
	p->next=temp;
	return true;
}

bool InsertNextNode(LNode *p,ElemType value){//在某个节点后插入value
	if(p==NULL)
		return false;
	LNode *temp=(LNode *)malloc(sizeof(LNode));
	if(temp==NULL)//内存分配失败
		return false;
	temp->data=value;
	temp->next=p->next;
	p->next=temp;
	return true;
}

bool InsertPriorNode(LNode *p,LNode *s){//在p节点前插入s
	if(p==NULL || s==NULL){
		return false;
	}
	s->next=p->next;
	p->next=s;
	ElemType temp=p->data;
	p->data=s->data;
	s->data=temp;
	return true;
}
bool ListDelete(LinkList &L,int index,ElemType value){
	if(index<1)
		return false;
	LNode *p;
	int pos=0;
	p=L;
	while(p!=NULL && pos<index-1){//遍历到第i-1个
		p=p->next;
		pos++;
	}
	if(p==NULL)
		return false;//非法
	if(p->next==NULL){
		return false;
	}
	LNode *temp=p->next;
	value=q->data;
	p->next=temp->next;
	free(temp);//释放节点
	return true;
}

bool DeleteNode(LNode *p){//删除指定节点
	if(p==NULL)
		return false;
	LNode *temp=p->next;
	p->data=temp->next->data;
	p->next=temp->next;
	free(temp);
	return true;
}

双链表

typedef struct DNode{
	ElemType data;
	struct DNode *prior,*next;
}DNode,*DLinkList;

bool InitDLinkList(DLinklist &L){//双链表初始化(带头结点)
	L=(DNode *) malloc(sizeof(DNode));
	if(L==NULL){
		return false;
	}
	L->prior=NULL;
	L->next=NULL;
	return true;
}

bool Empty(DLinkList L){
	return L->next==NULL;
}

bool InsertNextDNode(DNode *p,DNode *s){
	if(p==NULL || s==NULL){
		return false;
	}
	s->next=p->next;
	if(p->next!=NULL)
		p->next->prior=s;
	s->prior=p;
	p->next=s;
}

bool DeleteNextDNode(DNode *p){
	if(p==NULL){
		return false;
	}
	DNode *q=p->next;
	if(q==NULL){
		return false;
	}
	p->next=q->next;
	if(q->next!=NULL){
		q->next->prior=p;
	}
	free(q);
	return true;
}
void DestoryList(DLinkList &L){
	while(L->next!=NULL){
		DeleteNextNode(L);
	}
	free(L);
	L=NULL:
}

循环链表(第一个节点与最后一个节点相连)

循环单链表
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode,*LinkList;

bool InitList(LinkList &L){
	L=(LNode *)malloc(sizoef(LNode));
	if(L==NULL){
		return false;
	}
	L->next=L;//next指向头结点
	return true;
}
循环双链表
typedef struct DNode{
	ElemType data;
	struct DNode *prior,*next;
}DNode,*DLinkList;

bool InitDLinkList(DLinklist &L){//双链表初始化(带头结点)
	L=(DNode *) malloc(sizeof(DNode));
	if(L==NULL){
		return false;
	}
	L->prior=L;
	L->next=L;
	return true;
}

bool Empty(DLinkList L){
	return L->next==L;
}

bool isTail(DlinkList L,DNode *p){
	return p->next==L;
}

bool InsertNextDNode(DNode *p,Dnode *s){
	s->next=p->next;
	p->next->prior=s;
	s->prior=p;
	p->next=s;
}

void DeleteNextDNode(DNode *p){
	DNode *q;
	p->next=q->next;
	q->next->prior=p;
	free(q);
}

静态链表(用数组实现的链表)

#define MaxSize 10
typedef struct Node{
	ElemType data;
	int next;//下一个元素的下标
}SLinkList[MaxSize];

初始化:a[0].next=-1;
查找:顺序遍历
在第i个位置插入结点:

  1. 先找到空闲节点(比如负数表示空闲)存入元素
  2. 遍历找到第i-1个结点
  3. 修改新结点的next
  4. 修改i-1结点的next

删除某个节点:

  1. 遍历找到其前驱节点
  2. 修改前驱结点下标,被删除结点变为空闲状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值