【计算机考研数据结构代码题总结】链表

1.在带头节点的单链表L中,删除所有值为X的结点,并释放其空间,假设值为X的节点不唯一,试编写算法实现。

//单链表
//要放置三个指针,pre指向头结点(p结点的前驱),p指向头结点的下一个结点,q指向要被删除的结点
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

void Del_X(LNode *L, ElemType X){
	LNode *pre, *p, *q;
	pre = L;
	p = L->next;
	while(p != NULL){
		if(p->data == X){
			q = p;
			p = p->next;
			pre->next = p;
			free(q);
		}else{
			pre = p;
			p = p->next;
		}
	}
}

2.将两个非递减的有序表合并为一个非递增的有序表。要求结果链表仍然使用原来两个链表的存储空间,不占用另外的存储空间。表中允许有重复的数据。

//为保证新表与原表顺序相反,需要利用前插法建立单链表,而不能利用后插法
//当一个表到达表尾结点为空时,另一个非空表的剩余元素应该依次摘取,依次链接在 Lc 表的表头结点之后,而不能全部直接链接在 Lc 表的最后
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

void MergeList(LNode *a,LNode *b, LNode *&c)
{ 
	pa = a->next; 						//pa 是链表的 La 的工作指针,初始化为首元结点
	pb = b->next; 						//pb 是链表 Lb 的工作指针,初始化为首元结点
	c = pc = a; 						//用 a 的头结点作为 c 的头结点
	c->next = NULL;
	while(pa || pb) 					//只要有一个表未到达表尾指针,用 q 指向待摘取的元素
	{
		if(!pa) 						//a 表为空,用 q 指向 pb,pb 指针后移
		{
			q = pb;
			pb = pb->next;
		}
		else if(!pb) 					//b 表为空,用 q 指向 pa,pa 指针后移
		{
			q = pa;
			pa = pa->next;
		}
		else if(pa->data <= pb->data) 	//去较小者 a 中的元素,用 q 指向 pa,pa 指针后移
		{
			q = pa;
			pa = pa->next;
		}
		else 							//去较小者 b 中的元素,用 q 指向 pb,pb 指针后移
		{
			q = pb;
			pb = pb->next;
		}
		q->next = c->next;
		c->next = q;
	}
	free(b);
}

3.已知两个链表 A 和 B 分别为两个集合,其元素递增排列。请设计一个算法,用于求出 A 与 B 的交集,并存放在 A 链表中。

//依次摘取两个表中相等的元素重新进行链接,删除其他不等的元素。
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

void Intersection(LNode *La, LNode *Lb, LNode *&Lc)
{
	pa = La->next; 						//pa 是链表 La 的工作指针,初始化为首元结点
	pb = Lb->next; 						//pb 是链表 Lb 的工作指针,初始化为首元结点
	Lc = pc = La; 						//用 La 的头结点作为 Lc 的头结点
	while(pa && pb)
	{
		if(pa->data == pb->data) 		//相等,交集并入结果表中
		{
			pc->next = pa;
			pc = pa;
			pa = pa->next;
			u = pb;
			pb = pb->next;
			free(u);
		}
		else if(pa->data < pb->data) 	//删除较小者 La 中的元素
		{
			u = pa;
			pa = pa->next;
			free(u);
		}
		else 							//删除较小者 La 中的元素
		{
			u = pb;
			pb = pb->next;
			free(u);
		}
	}
	while(pa) 							//Lb 为空,删除非空表 La 中的所有元素
	{
		u = pa;
		pa = pa->next;
		free(u);
	}
	while(pb)							//La 为空,删除非空表 Lb 中的所有元素
	{
		u = pb;
		pb = pb->next;
		free(u);
	}
	pc->next = NULL;
	free(Lb)
}

4.试编写在带头结点的单链表 L 中删除一个最小值结点的高 效率 算法 ( 假设最小值结点是唯一的)。

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

LNode* Delete_Min(LNode *L)
{
	LNode *pre = L, *p = pre->next; 		//p 为工作指针,pre 指向其前驱
	LNode *minpre = pre, *minp = p; 		//保存最小值结点及其前驱
	while(p != NULL)
	{
		if(p->data < minp->data)
		{
			minp = p;
			minpre = pre;
		}
		pre = p; //继续扫描下一节点
		p = p->next;
	}
	minpre->next = minp->next; //删除最小值结点
	free(minp);
	return L;
}

5.在带头结点的单链表 L 中,删除所有值为 x 的结点,并释放其空间,假设值为 x 的结点不唯一,试编写算法实现上述操作。

//用 p 从头至尾扫描单链表,pre 指向*p 结点的前驱。
//若 p 所指结点的值为 x,则删除,并让 p 移向下一个结点,否则让 pre、p 同步后移一个结点。
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

void Delete_x(LNode *L, ElemType x)
{
	LNode *p = L->next, *pre = L, *q; 
	while(p != NULL)
	{
		if(p->data == x)
		{
			q = p; 				//q 指向该结点
			p = p->next;
			pre->next = p; 		//删除*q 结点
			free(q); 			//释放*q 结点的空间
		}
		else 					//否则,pre 和 p 同步后移
		{
			pre = p;
			p = p->next;
		}
	} 
}

6.设 C = {a 1 ,b 1 ,a 2 ,b 2 ,…,a n ,b n }为线性表,采用头结点的 hc 单链表存放,设计一个就地算法,将其拆分为两个单链表,使得 A = {a 1 ,a 2 ,…,a n },B = {b n ,…,b 2 ,b 1 }。

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

LNode* DisCreat(LNode *&A)
{
	LNode *&B = (LNode *)malloc(sizeof(LNode)); 
	B->next = NULL; 								//B 表的初始化
	LNode *p = A->next, *q; 						//p 为工作指针
	LNode *ra = A; 									//ra 始终指向 A 的尾节点
	while(p != NULL)
	{
		ra->next = p; ra = p; 						//将*p 链接到 A 的表尾
		p = p->next;
		q = p->next;
		p->next = B->next; 							//头插后,*p 将断链,因此 q 记忆*p 的后继
		B->next = p;					 			//*p 插入到 B 的前端
		p = q;
	}
	ra->next = NULL; 								//A 的尾节点的 next 域置空
	return B;
}

7.设计算法将一个带头结点的单链表 A 分解为两个具有相同结构的链表 B 和C,其中 B 表的结点为 A 表中小于零的结点,而 C 表中的结点为 A 表中值大于零的结点(链表 A 中的元素为非零整数,要求 B、C 表利用 A 表的结点)。

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

void Decompose(LNode *A, LNode *&B, LNode *&C)
{
	//单链表 A 分解为两个具有相同结构的链表 B 和 C
	B =A;
	B->next = NULL;
	C = (LinkList)malloc(sizeof(LinkList));
	C->next = NULL;
	p =A->next;
	while(p != NULL)
	{
		r = p->next; 					//暂存 p 的后继
		if(p->data < 0) 				//将小于 0 的结点插入 B 中,前插法
		{
			p->next = B->next;
			B->next = p;
		}
		else
		{
			p->next = C->next;
			C->next = p;
		}
		p = r; 							//p 指向新的待处理结点
	}
}

8.设计一个算法,通过一趟遍历确定长度为 n 的单链表中值最大的结点,返回该结点的数据域。

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

ElemType Max(LNode *L)
{
	//确定单链表中值最大的结点
	if(L->next == NULL)
		return NULL;
	pmax = L->next; 				//pmax 指向首元结点
	p = L->next->next; 				//p 指向第二个结点
	while(p != NULL) 				//遍历链表,如果下一个结点存在
	{
		if(p->data > pmax->data)
		pmax = p; 					//pmax 指向数值大的结点
		p = p->next; 				//p 指向下一个结点,继续遍历
	}
	return pmax->data;
}

9.设计一个算法,删除递增有序表中值大于 mink 且小于 maxk(mink 和 maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同)的所有元素。

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

void Delete_Min_Max(LNode *L, int mink, int maxk)
{
	//删除递增有序表 L 中值大于 mink 且小于 maxk 的所有元素
	p = L->next;
	while(p && p->data <= mink) 			//查找第一个值大于 mink 的结点
	{
		pre = p;
		p = p->next;
	}
	while(p && p->data < maxk) 				//查找第一个值大于等于 maxk 的结点
		p = p->next;
	q = pre->next;
	pre->next = p; 							//修改待删除结点的指针
	while(q != p) 							//依次释放待删除结点的空间
	{
		s = q->next;
		free(q);
		q = s;
	}
}

10.已知由单链表表示的线性表中,含有 3 类字符的数据元素(如:字母字符﹑数字字符和其他字符),试编写算法构造3个以循环链表表示的线性表,使每个表中只含同一类的字符,且利用原表中的节点空间作为这三个表的节点空间,头节点可另辟空间。

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

void Split(LNode *L, LNode * &A,LNode * &B,LNode * &C)
{
	LNode * p= L- > next,* q;
	A= (LNode *)malloc(sizeof(LinkList) );
	A->next = A;									//循环链表
	B= (LNode *) malloc(sizeof (LinkList));
	B->next = B;
	C= (LNode *)malloc(sizeof (LinkList));
	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 = p; 								//采用头插法建表 A
		}
		else if (p->data >='0' && p->data<= '9')
		{
			q = p;
			p = p->next;
			q->next = B->next;
			A->next = p; 								//采用头插法建表 B
		}
		else
		{
			q = p;
			p = p->next;
			q->next = C->next;
			C->next = p;								 //采用头插法建表 C
		}
	}
}

11.已知带头节点的循环单链表 L 中至少有两个节点,每个节点的两个字段为data 和 next,其中 data 的类型为整型。试设计一个算法判断该链表中每个元素的值是否小于其后续两个节点的值之和。若满足,则返回 true;否则返回 false。

typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

bool judge(LNode *L)
{
	LNode *p = L->next;
	bool b = true;
	while(p->next->next != L && b)
	{
		if(p->data > p->next->data + p->next->next->data)
		b = false;
		p = p->next;
	}
	return b;
}

12.给定一个链表,判断链表中是否有环。如果有环,返回 1,否则返回 0。

//快慢指针遍历链表,快指针步距为 2,慢指针步距为 1,如果链表带环,两指针一定会在环中相遇。
//判断极端条件,如果链表为空,或者链表只有一个结点,一定不会带环,直接返回 NULL
//创建快慢指针,都初始化指向头结点。因为快指针每次都要步进 2 个单位,所以在判断其自身有效性的同时还要判断其 next 指针的有效性,在循环条件中将两语句逻辑与并列起来
typedef struct LNode{
	int data;
	struct LNode *next;
}LNode;

int hasCycle(LNode *head)
{ 
	if(head == NULL || head->next == NULL)
		return 0;
	LNode *fast = head->next;
	LNode *slow = head;
	while(slow != fast)
	{
		if(fast == NULL || fast->next == NULL) //链表无环
			return 0;
		slow = slow->next;
		fast = fast->next->next;
	}
	return 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值