《数据结构》上机实验(第二章)——线性表 Ⅲ

参考书目:《数据结构教程(第五版)》 李春葆 主编
《2022年数据结构考研复习指导》 王道论坛 组编
《数据结构》上机实验(第二章) Ⅱ
在这里插入图片描述


1. L 1 = ( x 1 , x 2 , … , x n ) , L 2 = ( y 1 , y 2 , . . . , y m ) L1=(x_1,x_2,…,x_n),L2=(y_1,y_2,...,y_m) L1=(x1,x2,,xn)L2=(y1,y2,...,ym),它们是两个线性表,采用带头结点的单链表存储,合并L1、L2,结果放在线性表L3中。

要求如下:
L 3 = ( x 1 , y 1 , x 2 , y 2 , . . . , x m , y m , x m + 1 , . . . , x n )                      m ≤ n L3=(x_1,y_1,x_2,y_2,...,x_m,y_m,x_{m+1},...,x_n)\;\;\;\;\;\;\;\;\;\;m≤n L3=(x1y1x2y2...xmymxm+1...xn)mn
L 3 = ( x 1 , y 1 , x 2 , y 2 , . . . , x n , y n , y n + 1 , . . . , y m )                      m > n L3=(x_1,y_1,x_2,y_2,...,x_n,y_n,y_{n+1},...,y_m)\;\;\;\;\;\;\;\;\;\;m>n L3=(x1y1x2y2...xnynyn+1...ym)mn
L3仍采用单链表存储。

  • 算法思路:定义一个变量用来判断奇数、偶数,当该数为奇数时,复制x,当该数为奇数时,复制y,从而使L3中的值交替。
void Merge(LinkList &L1, LinkList &L2,LinkList &L3)
{
	LNode* p1 = L1->next, * p2 = L2->next, * p = L3, * r1;
	int i = 1;
	while (p1 != NULL && p2 != NULL) 
	{
		if (i % 2 == 1) //i为奇数时,把L1中的值放入L3
		{
			r1 = p1;
			p1 = p1->next;
			i++; //i的计数值+1
		}
		else //i为偶数时,把L2中的值放入L3
		{
			r1 = p2;
			p2 = p2->next;
			i++; //i的计数值+1
		}
		r1->next = p->next; //插入
		p->next = r1;
		p = p->next; //指针后移
	}
	if (p2 == NULL) r1->next = p1; //m≤n
	if (p1 == NULL) r1->next = p2; //m>n
}

程序分析:

  • 运行结果:
    在这里插入图片描述
  • 时间复杂度:O(m+n);空间复杂度:O(m+n)。其中m、n分别是L1、L2的长度。

2. 已知由单链表L表示的线性表中含有3类字符的数据元素(如字母、字符、数字字符和其他字符)。设计一个算法构造3个循环单链表A、B、C,使每个循环单链表中只含同一类的字符,且利用原表中的结点空间作为这3个表的结点空间,头结点可另辟空间。

  • 算法思想:先创建3个空的循环单链表,用p扫描单链表L的所有数据结点,将不同类型的结点采用头插法插入到相应的循环单链表中。
void Split(LNode* L, LNode*& A, LNode*& B, LNode* C)
{
	LNode* p = L->next, * q;
	A = L;
	A->next = A;
	B = (LNode*)malloc(sizeof(LNode));
	B->next = B;
	C = (LNode*)malloc(sizeof(LNode));
	C->next = C;
	while (p != NULL)
	{
		if (p->data >= 'A' && p->data <= 'Z' || p->data >= 'a' && p->data <= 'z')
		{
			q = p;
			p = p->next;
			q->next = A->next;
			A->next = q;
		}
		else if(p->data >= '0' && p->data <= '9')
		{
			q = p;
			p = p->next;
			q->next = B->next;
			B->next = q;
		}
		else
		{
			q = p;
			p = p->next;
			q->next = C->next;
			C->next = q;
		}
	}
}

3. 已知带头结点的循环单链表L中至少有两个结点,每个结点的两个域为data和next,其中data的类型为整型。判断该链表中每个结点值是否小于其后续两个结点值之和。

  • 解:用p扫描整个循环单链表L,一旦找到pー>data<pー>nextー>data+p->next->next->data条件不成立的结点p,则中止循环,返回假,否则继续扫描。当while循环正常结束时返回真。
bool fun(LinkList LA)
{
	LNode* p1 = LA->next, * p2, * p3;
	if (p1 != NULL && p1->next != NULL)
	{
		p2 = p1->next; //第一个后继结点
		if (p2 != NULL && p2->next != NULL) 
			p3 = p2->next; //第二个后继节点
	}
	while (p3 != NULL)
	{
		if (p1->data < p2->data + p3->data)
		{
			p1 = p1->next;
			p2 = p2->next;
			p3 = p3->next;
		}
		else return false;
	}
	return true;
}

程序分析:

  • 运行结果:
    在这里插入图片描述

4. 设计一个算法判定单链表L(带头结点)是否是递增的。

bool IsIncrease(LinkList LA)
{
	LNode* p = LA->next,*q;
	if (p != NULL) q = p->next; //第一个后继结点
	while (q != NULL)
	{
		if (q->data > p->data)
		{
			p = p->next;
			q = q->next;
		}
		else return false;
	}
	return true;
}

程序分析:

  • 运行结果:
    在这里插入图片描述

5. 一个长度为N的整型数组A[1…N],给定整数X,请设计一个时间复杂度不超过 O ( n l o g 2 n ) O(nlog_2^n) O(nlog2n)的算法,查找出这个数组中所有两两之和等于X的整数对(每个元素只输出一次)。

算法思想:先用一种时间复杂度为 O ( n l o g 2 n ) O(nlog_2^n) O(nlog2n)的排序算法将A[1…N]从小到大排序,可以用快速排序(或二路归并等),然后分别从数组的小端(i=1)和大端(j=N)开始査找;若A[i]+A[j]<X,i++若A[i]+A[j]>X,j-;否则输出A[i]、A[j],然后i++,j–;直到i>j停止。)



参考书目:《2022年数据结构考研复习指导》王道论坛 组编

1. 设计一个算法,删除不带头结点的单链表L中所有值为x的结点。

  • 不使用递归算法:
  • 算法思路:单链表L不带头结点,但可以把首结点看作是“头结点”,按照有头结点的单链表进行操作,最后再判断首结点的值是否为x。
void DeleteEle(LinkList& L,int x) //删除不带头结点的单链表L中所有值为x的结点
{
	LNode* pre = L, * p = L->next, * s = L, * p1; //pre和s都指向首结点,p指向第二个结点
	while (p != NULL)
	{
		if (p->data == x) //如果该结点值为x
		{
			if (p->next == NULL) pre->next = NULL; //如果要删除的值在尾结点,则前一个结点的指针域为NULL
			else pre->next = p->next; //如果要删除的值不在尾结点,则前一个结点的指针域指向该结点的下一个结点
			p1 = p; //让p1指向要删除的结点
			p = p->next; //p指针后移一个结点
			free(p1); //释放要删除的结点
		}
		else //如果该结点值不为x
		{
			pre = pre->next; //pre指针和p指针同时后移
			p = p->next;
		}
	}
	if (s->data == x) //s指向首结点,如果首结点的值为x
	{
		L = L->next; //首结点后移
		free(s); //释放首结点
	}
}

程序分析:

  • 运行结果:`
    在这里插入图片描述
  • 时间复杂度:O(n);空间复杂度:O(1)
  • 使用递归算法:
void del(LinkList &L,ElemType x)
{
	LNode* p;
	if (L == NULL) return;
	if (L->data == x)
	{
		p = L;
		L = L->next;
		free(p);
	}
	del(L->next, x);
}

程序分析:

  • 算法需要借助一个递归工作栈,深度为O(n),时间复杂度为O(n)。因为L为引用类型,是直接对原链表进行操作的,在此基础上free(p)结点不会造成断链。

2. 在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一。

  • 算法思路:参考第4题。
void DeleteEle(LinkList& L,int x)
{
	LNode* pre = L, * p = L->next, * p1;
	while (p != NULL)
	{
		if (p->data == x)
		{
			if (p->next == NULL) pre->next = NULL;
			else pre->next = p->next;
			p1 = p;
			p = p->next;
			free(p1);
		}
		else
		{
			pre = pre->next;
			p = p->next;
		}
	}
}

程序分析:

  • 运行结果:`
    在这里插入图片描述
  • 时间复杂度:O(n);空间复杂度:O(1)

3. 设L为带头结点的单链表,实现从尾到头反向输出每个结点的值。

  • 算法思路:先让p指向L的第二个结点,让L变为只含头结点和首结点的单链表,采用头插法实现单链表的逆置。
void DiverseEle(LinkList& L)
{
	LNode* p = L->next->next, * s = L, * pre;
	L->next->next = NULL;
	while (p != NULL)
	{
		pre = p;
		p = p->next;
		pre->next = s->next;
		s->next = pre;
	}
}

程序分析:

  • 运行结果:在这里插入图片描述

4. 在带头结点的单链表L中删除一个最小值结点(假设最小值结点是唯一的)

void DeleteEle(LinkList &L)
{
	LNode* premin = L, * min = L->next, * p=min, * s=premin;
	while (p != NULL)
	{
		if (p->data >= min->data)
		{
			s = s->next;
			p = p->next;
		}
		else
		{
			premin = s;
			min = p;
		}
	}
	if (min->next == NULL) premin->next = NULL;
	else premin->next = min->next;
	free(min);
}

程序分析:

  • 运行结果:在这里插入图片描述

5. 将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为O(1)。

算法思路:参考第6题。

6. 有一个带头结点的单链表L,使其元素递增有序。

7. 在一个带表头结点的单链表中所有元素结点的数据值无序,删除表中所有介于给定的两个值(作为函数参数给出)之间的元素(若存在)。

void DeleteEle(LinkList& L, int x, int y)
{
	LNode* pre = L, * p = L->next, * s;
	while (p != NULL)
	{
		if (p->data > x && p->data < y)
		{
			if (p->next == NULL) pre->next = NULL;
			else pre->next = p->next;
			s = p;
			p = p->next;
			free(s);
		}
		else
		{
			pre = pre->next;
			p = p->next;
		}
	}
}
DeleteEle(L, 0, 5);

程序分析:

  • 运行结果:在这里插入图片描述

8. 给定两个单链表,找出两个链表的公共结点。

9. 按递增次序输出单链表中各结点的数据元素,并释放结点所占的存储空间(要求:不允许使用数组作为辅助空间)。

10. 将一个带头结点的单链表A分解为两个带头结点的单链表A和B,使得A表中含有原表中序号为奇数的元素,而B表中含有原表中序号为偶数的元素,且保持其相对顺序不变。

  • 算法思路:Link:最上面的第一题。
void DepList(LinkList& L1, LinkList& L2)
{
	LNode* p1 = L1->next, * p2, * r = L2, * s;
	while (p1->next != NULL)
	{
		p2 = p1->next;
		s = p2;
		if (p2->next == NULL) p1->next = NULL;
		else p1->next = p2->next;
		p1 = p2->next;
		s->next = r->next;
		r->next = s;
		r = s;
	}
	r->next = NULL;
}

程序分析:

  • 运行结果:在这里插入图片描述

11. 设 C = { a 1 , b 1 , a 2 , b 2 , … , a n , b n } C=\{a_1,b_1,a_2,b_2,…,a_n,b_n\} C={a1,b1,a2,b2,,an,bn}为线性表,采用带头结点的hc单链表存放,设计一个就地算法,将其拆分为两个线性表,使得 A = { a 1 , a 2 , . . . , a n } , B = { b n , … , b 2 , b 1 } A=\{a_1,a_2,...,a_n\},B=\{b_n,…,b_2,b_1\} A={a1,a2,...,an}B={bn,,b2,b1}

  • 算法思路:Link:第1题
  • 可采用上题的思路,二者的区别在于上题使用尾插法,而这题使用头插法。
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值