线性表算法设计作业,C实现,完整可编译,严蔚敏数据结构第二版
最终完整代码详见文末,代码AC,文件后缀改成cpp
教材53页2.2题
将两个非递减的有序链表合并为一个非递增的有序链表,要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中允许有重复的数据。
算法如下,C描述
/*
线性表算法设计作业 教材53页2.2题
将两个非递减的有序链表合并为一个非递增的有序链表,要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中允许有重复的数据。
*/
void merge_down(LNode *&A, LNode *B) {
LNode *p = A->Next;
LNode *q = B->Next;
LNode *s;
A->Next = NULL;
free(B);
while(p !=NULL && q != NULL) {
//下边的if else语句体现了链表的头插法
if(p->data <= q->data) {
s = p;
p = p->Next;
s->Next = A->Next;
A->Next = s;
} else {
s = q;
q = q->Next;
s->Next = A->Next;
A->Next = s;
}
}
//下边两个循环是和求递增归并序列不同的地方,必须将剩余元素逐个插入C的头部才能得到最终的递减序列
while(p != NULL) {
s = p;
p = p->Next;
s->Next = A->Next;
A->Next = s;
}
while(q != NULL) {
s = q;
q = q->Next;
s->Next = A->Next;
A->Next = s;
}
}
运行结果:
教材53页2.3题
已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出A与B的交集,并存放于A链表中。
/*算法思想:采用归并的思想,设置两个工作指针pa和pb,对两个链表进行归并扫描,只有
同时出现在两集合中的元素才链接到结果表中且仅保留一个,其他的结点全部释放。当一个链表
遍历完毕后,释放另一个表中剩下的全部结点
*/
算法如下,C描述
/*
线性表算法设计作业 教材53页2.3题
已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出A与B的交集,并存放于A链表中。
*/
/*算法思想:采用归并的思想,设置两个工作指针pa和pb,对两个链表进行归并扫描,只有
同时出现在两集合中的元素才链接到结果表中且仅保留一个,其他的结点全部释放。当一个链表
遍历完毕后,释放另一个表中剩下的全部结点
*/
LNode * Union (LNode *&la,LNode *&lb) {
LNode *pa=la->Next;//设工作指针分别为pa和pb
LNode *pb=lb->Next;
LNode *pc=la;//结果表中当前合并结点的前驱指针
while (pa&&pb) {
if (pa->data==pb->data) {//交集并入结果表中
pc->Next=pa;//A中结点链接到结果表
pc=pa;
pa=pa->Next;
LNode * u=pb;//B中结点释放
pb=pb->Next;
free(u);
} else if (pa->data<pb->data) { //若A中当前结点值小于B中当前结点值
LNode * u=pa;
pa=pa->Next;//后移指针
free(u);//释放A中当前结点
} else { //若B中当前结点值小于A中当前结点值
LNode * u=pb;
pb=pb->Next;//后移指针
free(u);//释放B中当前结点
}
}//while结束
while (pa) {//B已遍历完,A未完
LNode * u=pa;
pa=pa->Next;
free(u);//释放A中剩余结点
}
while (pb) {//A已遍历完,B未完
LNode * u=pb;
pb=pb->Next;
free(u);//释放B中剩余结点
}
pc->Next=NULL;//置结果链表尾指针为NULL
free(lb);//释放B表的头结点
return la;
}
运行结果:
教材53页2.7题
设计一个算法,将链表中所有结点的链表方向“原地”逆转,即要求仅利用原表的存储空间,换句话说要求算法的空间复杂度为O(1)。
解法一:将头结点摘下,然后从第一结点开始,依次插入到头结点的后面(头插法建立单链表),直到最后一个结点为止,这样就实现了链表的逆置。
解法二 :假设pre、p和r指向3个相邻的结点,如下图所示。假设经过若干操作后,pre 之前的;
结点的指针都已调整完毕,它们的Next都指向其原前驱结点。现在令p结点的Next域指向
*pre结点,注意到一旦调整指针的指向后,p 的后继结点的链就会断开,为此需要用r来指向
原p的后继结点。处理时需要注意两点:一是在处理第一个结点时,应将其Next域置为NULL,
而不是指向头结点(因为它将作为新表的尾结点);二是在处理完最后一个结点后,需要将头结
点的指针指向它。
算法如下:C语言描述:
/*
线性表算法设计作业 教材53页2.7题
设计一个算法,将链表中所有结点的链表方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求算法的空间复杂度为O(1)。
*/
/*解法一:将头结点摘下,然后从第一结点开始,依次插入到头结点的后面(头插法建立单链
表),直到最后一个结点为止,这样就实现了链表的逆置
*/
LNode * Reverse_1 (LNode *L) {//L是带头结点的单链表,本算法将L就地逆置
LNode *p, *r;//p为工作指针,r为p的后继,以防断链
p=L->Next;//从第一个元素结点开始
L->Next=NULL;//先将头结点L的Next域置为NULL
while (p!=NULL) {//依次将元素结点摘下
r=p->Next;//暂存P的后继
p->Next=L->Next;//将P结点插入到头结点之后
L->Next=p;
p=r;
}
return L;
}
/*解法二 :假设pre、p和r指向3个相邻的结点,如下图所示。假设经过若干操作后,*pre 之前的;
结点的指针都已调整完毕,它们的Next都指向其原前驱结点。现在令*p结点的Next域指向
*pre结点,注意到一旦调整指针的指向后,*p 的后继结点的链就会断开,为此需要用r来指向
原*p的后继结点。处理时需要注意两点:一是在处理第一个结点时,应将其Next域置为NULL,
而不是指向头结点(因为它将作为新表的尾结点);二是在处理完最后一个结点后,需要将头结
点的指针指向它。
*/
LNode * Reverse_2 (LNode *L) {//依次遍历线性表L,并将结点指针反转
LNode *pre, *p=L->Next, *r=p->Next;
p->Next=NULL;//处理第一个结点
while(r!=NULL) {//r为空,则说明p为最后一个结点
pre=p;//依次继续遍历
p=r;
r=r->Next;
p->Next=pre;//指针反转
}
L->Next=p;//处理最后一个结点
return L;
}
运行结果:
教材53页2.8题
设计一个算法,删除递增有序链表中值大于mink且小于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。
算法如下,C语言描述:
/*
线性表算法设计作业 教材53页2.8题
设计一个算法,删除递增有序链表中值大于mink且小于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。
*/
void RangeDelete (LNode *&L, int mink, int maxk) {
LNode *pr = L, *p=L->Next;//p是检测指针,pr是其前驱
while (p !=NULL)
if (p->data>mink && p->data<maxk) { //寻找到被删结点,删除
pr->Next = p->Next;
free(p);
p = pr->Next;
} else {//否则继续寻找被删结点
pr = p;
p =p->Next;
}
}
运行结果:
教材53页2.10题
已知长度为n的线性表A采用顺序存储结构,请写一个时间复杂度为o(n)、空间复杂度为o(1)的算法, 该算法可删除线性表中所有值为item的数据元素。
算法如下,C语言描述:
/*
线性表算法设计作业 教材53页2.10题
已知长度为n的线性表A采用顺序存储结构,请写一个时间复杂度为o(n)、空间复杂度为o(1)的算法, 该算法可删除线性表中所有值为item的数据元素。
*/
/*解法一:用k记录顺序表L中不等于item的元素个数(即需要保存的元素个数),边扫描L边
统计k,并将不等于item的元素向前移动k个位置,最后修改L的长度。
*/
void del_item_1 (SqList &L, ElementType item) {//本算法实现删除顺序表L中所有值为item的数据元素
int k=0;//记录值不等于item的元素个数
for (int i=0; i<L.length; i++)
if (L.data[i] != item) {
L.data[k] = L.data[i];
k++;//不等于item的元素增 1
}
L.length=k;//更新顺序表L的长度等于k
}
/*解法二:用k记录顺序表L中等于item的元素个数,边扫描L边统计k,并将不等于item的元素
前移k个位置,最后修改L的长度。
*/
void del_item_2 (SqList &L, ElementType item) {
int k=0, i=0;//k记录值等于item的元素个数
while (i < L.length) {
if (L.data[i] == item)
k++;
else
L.data[i-k] = L.data[i]; //当前元素前移k个位置
i++;
}
L.length = L.length - k;//顺序表L的长度递减
}
运行结果:
以上各题的完整代码汇总
原创不易,期待三连支持
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 50
typedef int ElementType;
typedef struct LNode {
ElementType data;
struct LNode *Next;
} LNode;
typedef struct {
ElementType data[MaxSize];
int length;
} SqList;
/*
线性表算法设计作业 教材53页2.2题
将两个非递减的有序链表合并为一个非递增的有序链表,要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中允许有重复的数据。
*/
void merge_down(LNode *&A, LNode *B) {
LNode *p = A->Next;
LNode *q = B->Next;
LNode *s;
A->Next = NULL;
free(B);
while(p !=NULL && q != NULL) {
//下边的if else语句体现了链表的头插法
if(p->data <= q->data) {
s = p;
p = p->Next;
s->Next = A->Next;
A->Next = s;
} else {
s = q;
q = q->Next;
s->Next = A->Next;
A->Next = s;
}
}
//下边两个循环是和求递增归并序列不同的地方,必须将剩余元素逐个插入C的头部才能得到最终的递减序列
while(p != NULL) {
s = p;
p = p->Next;
s->Next = A->Next;
A->Next = s;
}
while(q != NULL) {
s = q;
q = q->Next;
s->Next = A->Next;
A->Next = s;
}
}
/*
线性表算法设计作业 教材53页2.3题
已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出A与B的交集,并存放于A链表中。
*/
/*算法思想:采用归并的思想,设置两个工作指针pa和pb,对两个链表进行归并扫描,只有
同时出现在两集合中的元素才链接到结果表中且仅保留一个,其他的结点全部释放。当一个链表
遍历完毕后,释放另一个表中剩下的全部结点
*/
LNode * Union (LNode *&la,LNode *&lb) {
LNode *pa=la->Next;//设工作指针分别为pa和pb
LNode *pb=lb->Next;
LNode *pc=la;//结果表中当前合并结点的前驱指针
while (pa&&pb) {
if (pa->data==pb->data) {//交集并入结果表中
pc->Next=pa;//A中结点链接到结果表
pc=pa;
pa=pa->Next;
LNode * u=pb;//B中结点释放
pb=pb->Next;
free(u);
} else if (pa->data<pb->data) { //若A中当前结点值小于B中当前结点值
LNode * u=pa;
pa=pa->Next;//后移指针
free(u);//释放A中当前结点
} else { //若B中当前结点值小于A中当前结点值
LNode * u=pb;
pb=pb->Next;//后移指针
free(u);//释放B中当前结点
}
}//while结束
while (pa) {//B已遍历完,A未完
LNode * u=pa;
pa=pa->Next;
free(u);//释放A中剩余结点
}
while (pb) {//A已遍历完,B未完
LNode * u=pb;
pb=pb->Next;
free(u);//释放B中剩余结点
}
pc->Next=NULL;//置结果链表尾指针为NULL
free(lb);//释放B表的头结点
return la;
}
/*
线性表算法设计作业 教材53页2.7题
设计一个算法,将链表中所有结点的链表方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求算法的空间复杂度为O(1)。
*/
/*解法一:将头结点摘下,然后从第一结点开始,依次插入到头结点的后面(头插法建立单链
表),直到最后一个结点为止,这样就实现了链表的逆置
*/
LNode * Reverse_1 (LNode *L) {//L是带头结点的单链表,本算法将L就地逆置
LNode *p, *r;//p为工作指针,r为p的后继,以防断链
p=L->Next;//从第一个元素结点开始
L->Next=NULL;//先将头结点L的Next域置为NULL
while (p!=NULL) {//依次将元素结点摘下
r=p->Next;//暂存P的后继
p->Next=L->Next;//将P结点插入到头结点之后
L->Next=p;
p=r;
}
return L;
}
/*解法二 :假设pre、p和r指向3个相邻的结点,如下图所示。假设经过若干操作后,*pre 之前的;
结点的指针都已调整完毕,它们的Next都指向其原前驱结点。现在令*p结点的Next域指向
*pre结点,注意到一旦调整指针的指向后,*p 的后继结点的链就会断开,为此需要用r来指向
原*p的后继结点。处理时需要注意两点:一是在处理第一个结点时,应将其Next域置为NULL,
而不是指向头结点(因为它将作为新表的尾结点);二是在处理完最后一个结点后,需要将头结
点的指针指向它。
*/
LNode * Reverse_2 (LNode *L) {//依次遍历线性表L,并将结点指针反转
LNode *pre, *p=L->Next, *r=p->Next;
p->Next=NULL;//处理第一个结点
while(r!=NULL) {//r为空,则说明p为最后一个结点
pre=p;//依次继续遍历
p=r;
r=r->Next;
p->Next=pre;//指针反转
}
L->Next=p;//处理最后一个结点
return L;
}
/*
线性表算法设计作业 教材53页2.8题
设计一个算法,删除递增有序链表中值大于mink且小于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。
*/
void RangeDelete (LNode *&L, int mink, int maxk) {
LNode *pr = L, *p=L->Next;//p是检测指针,pr是其前驱
while (p !=NULL)
if (p->data>mink && p->data<maxk) { //寻找到被删结点,删除
pr->Next = p->Next;
free(p);
p = pr->Next;
} else {//否则继续寻找被删结点
pr = p;
p =p->Next;
}
}
/*
线性表算法设计作业 教材53页2.10题
已知长度为n的线性表A采用顺序存储结构,请写一个时间复杂度为o(n)、空间复杂度为o(1)的算法, 该算法可删除线性表中所有值为item的数据元素。
*/
/*解法一:用k记录顺序表L中不等于item的元素个数(即需要保存的元素个数),边扫描L边
统计k,并将不等于item的元素向前移动k个位置,最后修改L的长度。
*/
void del_item_1 (SqList &L, ElementType item) {//本算法实现删除顺序表L中所有值为item的数据元素
int k=0;//记录值不等于item的元素个数
for (int i=0; i<L.length; i++)
if (L.data[i] != item) {
L.data[k] = L.data[i];
k++;//不等于item的元素增 1
}
L.length=k;//更新顺序表L的长度等于k
}
/*解法二:用k记录顺序表L中等于item的元素个数,边扫描L边统计k,并将不等于item的元素
前移k个位置,最后修改L的长度。
*/
void del_item_2 (SqList &L, ElementType item) {
int k=0, i=0;//k记录值等于item的元素个数
while (i < L.length) {
if (L.data[i] == item)
k++;
else
L.data[i-k] = L.data[i]; //当前元素前移k个位置
i++;
}
L.length = L.length - k;//顺序表L的长度递减
}
/*尾插法建立链表L */
void createListR(LNode *&L) {
LNode *s, *r; //s用来指向新申请的结点,r始终指向L的终端结点
ElementType x;
L = (LNode *)malloc(sizeof(struct LNode));//申请L的头结点空间
L->Next = NULL;
r = L;//r指向头结点,因为此时头结点就是终端结点
printf("\n(尾插法)请依次输入链表元素(以-999作结束标志):\n");
while(1) { //循环申请结点来接收输入缓冲区中的元素,直到遇到-999结束接收
scanf("%d",&x);
if(x == -999) break;
s = (LNode *)malloc(sizeof(struct LNode));//s指向新申请的结点
s->data = x;//用新申请的结点来接收输入的元素
r->Next = s;//用r来接纳新结点
r = r->Next;//r指向终端结点,以便于接纳下一个到来的结点
}
r->Next = NULL;//输入缓冲区的所有元素都已经装入链表L中,L的终端结点的指针域置位NULL,L建立完成
}
/*头插法建立链表L */
void createListF(LNode *&L) {
LNode *s;
ElementType x;
L = (LNode *)malloc(sizeof(struct LNode));
L->Next = NULL;
printf("\n创建链表(头插法)---请依次输入链表元素(以-999作结束标志):\n");
while(1) {
scanf("%d",&x);
if(x == -999) break;
s = (LNode *)malloc(sizeof(struct LNode));
s->data = x;
//下边两句是头插法的关键步骤
s->Next = L->Next;//s所指新结点的指针域Next指向L中的开始结点
L->Next = s;//头结点的指针域Next指向s结点,使得s成为新的开始结点
}
}
/*打印链表*/
void printList(LNode *L) {
LNode *p = L->Next;
// printf("\n链表元素依次为:");
while(p != NULL) {
printf("%d ",p->data);//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
p = p->Next;
}
printf("\n");
}
/*创建线性表*/
void createSqList(SqList &L) {
int i = 0;
L.data[MaxSize] = 0;
L.length = 0;
ElementType e;
printf("\n创建线性表------请输入线性表元素(以-999结束输入):");
while (1) {
scanf("%d",&e);
if (e == -999) break;//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
L.data[i++] = e;
L.length++;
if (L.length > MaxSize) {
printf("超出MaxSize\n");//leidata Structure
break;
}
}
}
//输出顺序表中元素
void ShowSqList(SqList L) {
int i;
// printf("\n线性表为:");
for (i = 0; i < L.length; i++) {
printf("%d ", L.data[i]);//Lei DataStructure
}
printf("\n");
}
void showMenu() {
printf("******************************线性表算法设计题作业******************************\n");
printf("1.教材53页2.2题 将两个非递减的有序链表合并为一个非递增的有序链表,要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中允许有重复的数据。\n");
printf("2.教材53页2.3题 已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出A与B的交集,并存放于A链表中。\n");//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
printf("3.教材53页2.7题 设计一个算法,将链表中所有结点的链表方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求算法的空间复杂度为O(1)。\n");
printf("4.教材53页2.8题 设计一个算法,删除递增有序链表中值大于mink且小于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。\n");
printf("5.教材53页2.10题 已知长度为n的线性表A采用顺序存储结构,请写一个时间复杂度为o(n)、空间复杂度为o(1)的算法, 该算法可删除线性表中所有值为item的数据元素。\n");
printf("0.退出并返回上一级\n\n");
printf("请输入你的选择:\n");
}
int main() {
LNode *La,*Lb;
SqList L;
ElementType mink,maxk;
ElementType item;
int choice = -1;
while(1) {
system("cls");//Lei Data Structure
showMenu();
scanf("%d",&choice);
if(choice == 0) break;//lei Data Structure
fflush(stdin);
switch (choice) {//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
case 1:
printf("创建链表La(元素非递减有序):");
createListR(*&La);//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
printf("创建链表Lb(元素非递减有序):");
createListR(*&Lb);
merge_down(La, Lb);
printf("归并成非递增的链表(仍使用原来两个链表的存储空间):");
printList(La);
system("pause");//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
break;
case 2:
printf("链表A(元素递增排列):");//leiDataStructure
createListR(*&La);
printf("链表B(元素递增排列):");
createListR(*&Lb);
Union(*&La,*&Lb);//leiDataStructure
printf("求出A与B的交集,并存放于A链表中:\n");
printList(La);
system("pause");
break;
case 3:
createListR(*&La);
La = Reverse_2 (La);//leiDataStructure
printf("链表就地逆转后:");
printList(La);
system("pause");//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
break;
case 4:
createListR(*&La);
printf("输入 mink 和 maxk:");
scanf("%d %d",&mink,&maxk);
RangeDelete(*&La,mink,maxk);
printf("删去介于%d和%d之间的所有元素后:",mink,maxk);
printList(La);
system("pause");//leiDataStructure
break;
case 5:
createSqList(L);
printf("input item that you want to delete:");
scanf("%d",&item);
del_item_1(L, item);//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
printf("after delete %d:\n",item);
ShowSqList(L);
system("pause");//https://blog.youkuaiyun.com/lei20172017?spm=1010.2135.3001.5343
break;
default:
printf("\n无效选择,请重新输入!\n");
system("pause");
break;
}
}
return 0;
}