博客作业2---线性表
一、PTA实验作业(5分)
题目1: jmu-ds- 顺序表删除重复元素
2. 设计思路(伪代码或流程图)
新建顺序表函数:
应用地址L,传入数组a【】和长度n
L申请空间
定义变量i
for(i=0;i<n;i++)
将数组a中元素转移到L中
L的长度改为n
展示表中元素函数:
传入顺序表L
定义变量i
for(i=0;i<L->length;i++)
输出L->data[i]
不到最后一个元素都输出空格
删除相同元素函数:
引用顺序表L
定义变量i,j,k
for(i=1;i<L->length;i++){
for(j=0;j<i;j++){
if(L->data[i]==L->data[j])找到相同元素
移动后面元素删除相同元素
L长度减少
i--,从该位置开始判断
end
end
3.代码截图
4.PTA提交列表说明。
该题提交结果提交时,只出现了段错误,没有其他的错误,一直找不到原因,一直修改删除相同数据的函数,不断提交,结果最多就只有空表的数据点正确。
解决方法:看了一眼其他同学的代码,发现新建顺序表时,没有给L申请空间,但是devc++编译没出现问题,所以一直没发现,修改后就对了。
题目2:jmu-ds-单链表逆置
2. 设计思路(伪代码或流程图)
新建单链表函数:
应用地址L,传入长度n
新建指针p和tail
L申请空间
初始化L为空的单链表
tail赋值L,形成尾指针
定义int变量num存元素
while(n--)
输入num
p节点申请空间
p->data变为num
p->next为空
连接p与L
尾节点移动到p
end
展示表中元素函数:
传入单链表L
定义指针l进行链表间移动
if(L为空链表)输出NULL
while(l不为空)
输出l->data
不到最后一个元素都输出空格
l移动到下一个节点
end
单链表逆序函数:
引用单链表L
定义List指针p=L->next得到L的后续节点,并定义一个q暂存节点
L链表初始化为空
while(p不为空时)
q从p中取出一个节点
p移动到下一个
q节点为插到L的后面
end
3.代码截图
4.PTA提交列表说明。
思路清晰,在devc++上验证好多遍,上交后有一个错误:空表时格式错误,结果是因为输出时没检查空表,加上一句判断后结果正确。
题目3:集合的基本运算
2. 设计思路(伪代码或流程图)
新建单链表函数:
应用地址L,传入长度n和数组a
新建指针p和tail
L申请空间
初始化L为空的单链表
tail赋值L,形成尾指针
定义变量i
for(i=0;i<n;i++)
p节点申请空间
将数组a中元素转移到p->data
p->next为空
连接p与L
尾节点移动到p
end
展示表中元素函数:
传入单链表L
定义指针l进行链表间移动
if(L为空链表)输出NULL
while(l不为空)
输出l->data加空格
l移动到下一个节点
输出换行
end
摧毁单链表函数:
引用L
定义链表指针p
while(L)
p=L
L下移
删除p
end
排序的函数:
引用L
定义链表指针p继承L后续节点,q存放取出的节点,l在新建链表上移动,pre用于连接
L->next=NULL
while(p)
q=p取出节点
p下移
if第一个节点,直接插入
else
pre=L
l=L->next
while(l不为空)
if(l->data大于q->data)
插入q在该元素前面
停止循环
if(l到达尾)
q直接插到末尾
停止循环
l指向下一个
end
end
求并集的函数:
传入ha,hb,引用hc
定义链表指针p和tail当成尾节点
hc申请空间并初始化
尾节点初始化到hc
ha=ha->next;hb=hb->next从有效点开始操作
while(ha||hb)两条链表都结束才结束
p申请空间
if(hb为空或ha->data小于hb->data)
ha的data给p的data
p->next为空
连接p到hc
ha移动到下一个
else if(ha为空或ha->data大于hb->data)
hb的data给p的data
p->next为空
连接p到hc
hb移动到下一个
else if(ha->data等于hb->data)
hb的data给p的data
p->next为空
连接p到hc
ha,hb移动到下一个
end
求交集函数:
传入ha,hb,引用hc
定义链表指针p和tail当成尾节点
hc申请空间并初始化
尾节点初始化到hc
ha=ha->next;hb=hb->next从有效点开始操作
while(ha||hb)两条链表都结束才结束
p申请空间
if(hb为空或ha->data小于hb->data)
ha移动到下一个
else if(ha为空或ha->data大于hb->data)
hb移动到下一个
else if(ha->data等于hb->data)
hb的data给p的data
p->next为空
连接p到hc
ha,hb移动到下一个
end
求差集函数:
传入ha,hb,引用hc
定义链表指针p和tail当成尾节点,h存ha和hc交集
h申请空间并初始化
调用函数求ha和hc交集到h
hc申请空间并初始化
尾节点初始化到hc
ha=ha->next;h=h->next从有效点开始操作
while(ha||h)两条链表都结束才结束
p申请空间
if(h为空或ha->data小于h->data)
ha的data给p的data
p->next为空
连接p到hc
ha移动到下一个
else if(ha为空或ha->data大于h->data)
h的data给p的data
p->next为空
连接p到hc
h移动到下一个
else if(ha->data等于hb->data)
ha,hb移动到下一个
end
3.代码截图
4.PTA提交列表说明。
开始的错误有段错误和答案错误,多错误的原因就是空指针是让他指向了data,修改了循环和一些条件就可以了,改动的地方很多很杂,不便具体指出,然后就是答案错误,具体原因是求差集的函数理解错误,以为是a并b-a交b,结果是a-b,理解后改了下就对了。
二、截图本周题目集的PTA最后排名(3分)
1.顺序表PTA排名
2.链表PTA排名
3.我的总分:270
三、本周学习总结(2分)
1.谈谈你本周数据结构学习时间是如何安排,对自己安排满意么,若不满意,打算做什么改变?(1分)
学习时间都是预习作业一出来就开始本章的预习,先翻翻课本了解一下,在通过课堂派的习题深入了解知识点,等到真正上课时认真听老师讲解本章的知识点,稍微记录下老师讲过的但课本上没有的重要内容,最后通过pta综合一下,融会贯通,能熟练运用于实践的代码编程。编程的时间安排一般是找时间比较长的时间段,不如晚自习放学回宿舍,或礼拜天,一起做几题出来,一般一个时间段能做三四题。不懂问题时一般先在宿舍内讨论下,基本能得到解决。安排还算满意,能够保持下去就可以了。
2.谈谈你对线性表的认识?(1分)
线性表就是将一串数据连接起来成线性结构,方便对这串数据进行操作的一种结构.
线性表主要主要有两种存储结构:顺序结构和链式结构
1.顺序结构/顺序表
顺序表在计算机内占有一块连续的内存,可以通过下标直接访问到表中元素,但是删除表中元素时就要对其他元素做移动。
结构体定义样例:
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
基本操作合集:
//销毁顺序表
void FreeList_sq(SqList &L){
if (L.elem)
free(L.elem);
printf("完成链表内存销毁\n");
}
//在顺序表的第i个位置之前插入新元素
int ListInsert_sq(SqList &L, int i, ElemType e){
int k;
if (i<1 || i>L.length + 1)
return ERROR; /*插入位置不合法*/
if (L.length >= L.listsize){ /*存储空间满,重新分配空间*/
L.elem = (ElemType*)realloc(L.elem, (LIST_INIT_SIZE + INCREM)*sizeof(ElemType));
if (!L.elem) return OVERFLOW; /*存储分配失败*/
L.listsize += INCREM; /*修改存储空间大小*/
}
for (k = L.length - 1; k >= i - 1; k--){ /*插入位置之后元素后移*/
L.elem[k + 1] = L.elem[k];
}
L.elem[i - 1] = e; /*插入元素*/
L.length++; /*顺序表长度加1*/
return OK;
}/*ListInsert*/
//遍历并输出顺序表所有元素
void PrintList_sq(SqList &L){
if (!L.elem) return;
int i = 0;
for (i = 0; i < L.length; i++)
printf("第[%d]元素= [%d]\n", i, L.elem[i]);
}
//删除顺序表第i个位置的元素
int ListDelete_sq(SqList &L, int i,ElemType &e){
int k;
if (i<1 || i>L.length)
return ERROR; /*删除位置不合法*/
e = L.elem[i-1];
for (k = i - 1; k<L.length - 1; k++) /*元素前移*/
L.elem[k] = L.elem[k + 1];
L.length--; /*顺序表长度减1*/ return OK;
}
//在顺序表里查找出第1个与e相等的数据元素位置
int LocateElem_sq(SqList L,ElemType e){
int i = 0;
while(i<=L.length){
if(L.elem[i] == e)
break;
else
i++;
}
if(i<=L.length)
return i;
return -1;
}
//已知线性表La和Lb的元素按值非递减排列 //归并后的La和Lb得到新的顺序线性表Lc,Lc的元素也是按值非递减排列
void MergeList_sq(SqList La,SqList Lb, SqList &Lc){
ElemType *pa = La.elem;
ElemType *pb = Lb.elem;
Lc.listsize = Lc.length = La.length + Lb.length;
if(!Lc.elem) exit(OVERFLOW); //存储分配失败
int i = 0,j = 0;
int k =0; //i指向La的当前位置,j指向Lb当前位置,k指向Lc当前位置
while(i<La.length && j<Lb.length){ //归并
if(La.elem[i]<Lb.elem[j]){
Lc.elem[k] = La.elem[i];
i++;
}
else{
Lc.elem[k] = Lb.elem[j];
j++;
}
k++;
}
while(i<La.length)
Lc.elem[k++] = La.elem[i++];
while(j<La.length)
Lc.elem[k++] = Lb.elem[j++];
}
//判断顺序表是否为空
bool ListEmpty(SqList &L){
if(L.length > 0)
return 1;
else
return 0;
}
2.链式结构/单链表,双链表,循环链表
链表存储更叫灵活,不依赖物理上内存的位置,可以进行任意的增加和删除,即增加减少节点即可,但是查找时这要遍历链表方能找到。
结构体定义:
typedef char ElemType;
typedef struct LNode //定义单链表结点类型
{
ElemType data;
struct LNode *next;
} LinkList;
基本操作集合:
//销毁单链表表
void FreeList_L(LinkList L){
LinkList p = L;
while (p){
L = L->next;
free(p);
p = L;
}
}
//在单链表的第i个位置之前插入新元素
Status ListInsert_L(LinkList &L, int i, ElemType e){
LinkList p = L;
int j = 0;
while(p && j<i-1){ //寻找第i-1个结点
p = p->next;
++j;
}
if(!p || j>i)
return ERROR;
LinkList s = (LinkList)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
//遍历并输出单链表所有元素
void PrintList_L(LinkList L){
int i = 0;
LinkList p = L->next;
while (p){
printf("第[%d]元素= [%d]\n", i++, p->data); p = p->next;
}
}
//获取单链表第i个位置的元素
Status GetElem_L(LinkList L,int i,ElemType &e){ //L为带头结点的单链表的头指针
//当第i个元素存在,其值赋给e并返回OK,否则返回ERROR
LinkList p = L->next;
int j = 1;
while(p && j<i){
p = p->next;
++j;
}
if(!p)
return ERROR; //第i个元素不存在
e = p->data;
return OK;
}
//删除单链表第i个位置的元素,并由e返回其值
Status ListDelete_L(LinkList &L, int i, ElemType &e){
LinkList p = L;
int j = 0;
while(p->next && j<i-1){
//寻找第i个结点,并令p指向其前驱
p = p->next;
++j;
}
if(!p->next || j>i-1)
return ERROR; //删除位置不合理
LinkList q = p->next;
p->next = q->next;
e = q->data;
free(q);
return OK;
}
//单链表翻转,不增加额外的存储空间
void ListConvert_L(LinkList &L) {
LinkList p,q;
p=L->next;
L->next=NULL;
while(p){
q=p;
p=p->next;
q->next=L->next;
L->next=q;
}
}
3.代码Git提交记录截图
四、阅读代码(选做,加1分)
找1篇优秀代码贴图展示,并说明该代码功能是什么,优点是什么?
代码可以是自己同学代码,也可以是其他地方找的代码。
线性表合并运算函数:
void mergeList(SeqList *LA, Seqlist *LB, Seqlist *LC)
{
int i,j,k;
i=0; j=0; k=0;
while(i <= LA->last || j <= LB->last)
if(LA->elem[i] <= LB->elem[i] || (i <= LA->last && j > LB->last ))
{
LC->elem[k] = LA->elem[i];
i++; k++;
}
if(LA->elem[i] > LB->elem[j] || (i > LA->last && j <= LB->last))
{
LC->elem[k] = LB->elem[i];
j++; k++;
}
}
功能:将两条顺序表中的元素合并并从小到大排列。
优点:循环结束的条件是两条有序的线性表都走到空时才停止循环,虽然有可能出现下标越界的风险但是合理控制了这种情况,利用条件判断,当一条链表为空时,填入另一条链表的值,是程序大大简化。