数据结构与算法 --C++
数据结构与算法
函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#INFEASIBLE -1
#OVERFLOW -2
typedef int Status;
typedef char ElemType;
1.线性表
结构体
define MAXSIZE 100
typedef struct{
ElemType *elem;
int length;
} SqList;
1) 线性表L的初始化
Status InitList_Sq(SqList &L){ //构造一个空的顺序表
L.elem = new ElemType[MAXSIZE]; //为顺序表分配空间
if(!L.elem) exit(OVERFLOW); //存储分配失败
L.length = 0; //空表长度为0
return OK;
}
2) 查找
int LocateElem(SqList L, ElemType e){
for(i = 0; i < L.length; i++)
if(L.elem[i] == e) return i+1;
return 0;
}
3) 插入
Status ListLnsert_Sq(SqList &L, int i, ElemType e){
if(i < 1 || i > L.length+1) return ERROR; //i值不合法
if(L.length == MAXSIZE) return ERROR; //当前存储空间已满
for(j = L.length-1; j >= i-1; j--)
L.elem[j+1] = L.elem[j]; //插入位置及之后的元素后移
L.elem[i-1] = e; //将新元素e放入第i个位置
L.length++; //表长增1
return OK;
}
4)线性表的合并
- 问题描述:假设利用两个线性表La和Lb分别表示两个集合A和B,现要求一个新的集合A=A∪B
La=(7,5,3,11) Lb=(2,6,3) ----------> La=(7,5,3,11,2,6) - 算法步骤: 依次取出Lb中的每个元素
-
- 在La中查找该元素
-
- 如果找不到,则将其插入La的最后
void union(List &La, List Lb){
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);
}
}
5)有序表的合并
-
问题描述:已知线性表La和Lb中的数据元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列
La={1,7,8} Lb={2,4,6,8,10,11} -------> Lc= -
算法步骤:
-
- 创建一个空表Lc
-
- 依次从La或Lb中”摘取“元素值较小的结点插入到Lc表的最后,直至其中一个表变空为止
-
- 继续将La或Lb其中一个表的剩余结点插入在Lc表的最后
void MergeList_Sq(SqList LA, SqList LB, SqList &LC){
pa = LA.elem; //pa = LA.elem[0]
pb = LB.elem; //指针pa和pb的初值分别指向两个表的第一个元素
LC.length = LA.length + LB.length; //新表长度为待合并量表的长度之和
LC.elem = new ElemType[LC.length]; //为合并后的新表分配一个数组空间
pc = LC.elem; //指针pc指向新表的第一个元素
pa_last = LA.elem + LA.length -1; //指针pa_last指向LA表的最后一个元素
pb_last = LB.elem + LB.length -1; //指针pb_last指向LB表的最后一个元素
while(pa<=pa_last && pb<=pb_last){ //两个表都非空
if(*pa<=*pb) *pc++=*pa++; //依次”摘取“两表中值较小的结点
else *pc++=*pb++;
}
while(pa<=pa_last) *pc++=*pa++; //LB表已到达表尾,将LA中剩余元素加入LC
while(pb<=pb_last) *pc++=*pb++; //LA表已到达表尾,将LB中剩余元素加入LC
}
//这里的LA.elem+LA.length-1就等同于LA.elem[0+La.length-1]
6)删除数据
bool DeleteData(SqList &pa, int n){
if((n<1) || (n > pa.length + 1))
return false; //返回值为错误
for(int i = 1; i < pa.length - 1; i++)
pa.elem[i-1] = pa.elem[i]; //删除数据后,将数据所对应的线性表进行修改
pa.length--; //线性表的长度将减少
return true; //返回值为正确
}
2.单链表
结构体
typedef struct Lnode{
ElemType data;
struct Lnode *next;
}LNode,*LinkList;
1) 初始化
Status InitList_L(LinkList &L){
L = new LNode;
L->next = NULL;
return OK;
}
2) 判断链表是否为空
int ListEmpty(LinkList L){
if(L->next)
return 0;
else
return 1;
}
3) 单链表的销毁
Status DestroyList_L(LinkList &L){
Lnode *p; //或LinkList p;
while(L){
p = L;
L = L->next;
delete p;
}
4) 清空链表
Status ClearList(LinkList &L){
Lnode *p,*q; //或LinkList p,q;
p=L->next;
while(p){
q = p->next;
delete p;
p = q;
}
L->next = NULL;
return OK;
}
5) 单链表的表长
int ListLength_L(LinkList L){ //返回L中数据元素个数
LinkList p;
p = L->next; //p指向第一个结点
i = 0;
while(p){ //遍历单链表,统计结点数
i++;
p = p->next;
}
return i;
}
6) 单链表的取值
Status GetElem_L(LinkList L, int i, ElemType &e){ //获取线性表L中的某个数据元素的内容,通过变量e返回
p = L->next; j = 1;
while(p && j < i){ //向后扫描,直到p指向第i个元素或p为空
p=p->next; j++;
}
if(!p || j>i) return ERROR; //第i个元素不存在
e = p->data; //取第i个元素
return OK;
} //GetElem_L
7) 单链表的查找
- 按值查找:根据指定数据获取该数据所在的位置(该数据的地址)
Lnode *LocateELem_L(LinkList L, Elemtype e){
//在线性表L中查找值为e的数据元素
//找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
p = L->next;
while(p && p->data != e)
p = p->next;
return p;
}
- 按值查找:根据指定数据获取该数据所在的位置序号(是第几个数据元素)
//在线性表L中查找值为e的数据元素的位置序号
int LocateELem_L(LinkList L, Elemtype e){
//返回L中值为e的数据元素的位置序号,查找失败返回0
p = L->next; j = 1;
while(p && p->data != e){
p = p->next;
j++;
}
if(p) return j;
else return 0;
}
8) 单链表的插入
//在L中第i个元素之前插入数据元素e
Status ListInsert_L(LinkList &L, int i,ElemType e){
p = L; j = 0;
while(p && j<i-1){
p = p->next; j++; //寻找第i-1个结点,p指向i-1结点
}
if(!p || j>i-1) return ERROR; //i大于表长+1或者小于1,插入位置非法
s = new LNode; s->data = e; //生成结点s,将结点s的数据域置为e
s->next = p->next; //将结点s插入L中
p->next = s;
return OK
} //ListInsert_L
9) 单链表的删除
//将线性表L中第i个数据元素删除
Status ListDelete_L(LinkList &L, int i, ElemType &e){
p = L; j = 0;
while(p->next && j<i-1){
p = p->next;
j++;
} //寻找第i个结点,并令p指向其前驱
if(!(p->next) || j>i-1) return ERROR; //删除位置不合理
q = p->next; //临时保存被删结点的地址以备释放
p->next = q->next; //改变删除结点前驱结点的指针域
e = q->data; //保存删除结点的数据域
delete q; //释放删除结点的空间
return OK;
} //ListDelete_L
10)单链表的建立
- 头插法
void CreateList_H(LinkList &L, int i){
L = new LNode;
L->next = NULL;
for(i=n;i>0;i--){
p = new LNode;
cin >> p->data;
p->next = L->next; //插入到表头
L->next = p;
}
}
- 尾插法
void CreateList_T(LinkList &L, int n){
L = new LNode;
L->next = NULL;
r = L; //尾指针r指向头结点
for(i=1; i<=n; i++){
p = new LNode;
cin >> p->data;
p->next = NULL;
r->next = p; //插入到表尾
r = p; //r指向新的尾结点
}
}
3.单循环链表(表的操作常常是在表的首尾位置上进行)
循环链表
带尾指针循环链表的而合并(将Tb合并在Ta之后)
LinkList Connect(LinkList &Ta, LinkList &Tb){
//假设Ta,Tb都是非空的单循环链表
p = Ta->next; //p存储头结点
Ta->next = Tb->next->next; //Tb表头连结Ta表尾
delete Tb->next; //释放Tb表头结点
Tb->next = p; //修改指针
return Tb;
}
4.双向链表
- 在单链表的每个结点里再增加一个指向其直接前驱的指针域,这样链表中就形成了有两个方向不同的链
双向循环链表:
- 让头结点的前驱指针指向链表的最后一个结点
- 让最后一个结点的后继指针指向头结点
双向链表结构的对称性(设指针p指向某一结点)
- p->prior->next = p = p-next->prior
结构体定义
typedef struct DuLNode{
Elemtype data;
struct DuLNode *prior, *next;
}DuLNode, *DuLinkList;
1)双向链表的插入
//在常头结点的双向循环链表L中第i个位置之前插入元素e
void ListInsert_DuL(DuLinkList &L, int i, ElemType e){
if(!(p = GetElemP_DuL(L,i))) return ERROR;
s = new DuLNode; s->data = e;
s->prior = p->prior; p->prior->next = s;
s->next = p; p->prior = s;
return OK;
}//ListInsert_DuL
2)双向链表的删除
void ListDelete_DuL(DuLink &L, int i, ElemType &e){
//删除带头结点的双向循环链表L的第i个元素,并用e返回
if(!(p = GetElemP_DuL(L,i))) return ERROR;
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
delete p;
return OK;
}//ListDelete_DuL
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!