线性表算法设计作业,C实现,完整可编译,严蔚敏数据结构第二版

线性表算法设计作业,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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值