链表面试题

本文涵盖了链表的多种操作,包括从尾到头打印、删除非尾节点、插入节点、实现约瑟夫环、链表逆置、排序、合并有序链表、查找中间节点、寻找相同数据、找到倒数第k个节点、判断链表相交及环的属性等复杂问题,适合链表算法复习和面试准备。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 链表的结构

typedef struct Node
{
	DataType data;
	struct Node* next;
}Node, *pNode;
  • 链表的基本函数

//初始化
void InitLinList(pNode* pn)
{
	assert(pn);
	*pn = NULL;
}

//创建新的节点
Node* CreatNewNode(DataType d)
{
	Node* node = (Node*)malloc(sizeof(Node));
	node->data = d;
	node->next = NULL;
	return node;
}


//打印
void PrintLinList(pNode first)
{
	Node* cur = first;
	printf("first-->");
	while (cur != NULL)
	{
		printf("%d-->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}


//尾插
void PushBack(pNode* pn, DataType d)
{
	assert(pn);
	Node* cur = *pn;

	Node* newnode = CreatNewNode(d);

	//链表为空
	if (*pn == NULL)
	{
		*pn = newnode;
		return;
	}

	//至少有一个数据
	while (cur->next != NULL)
	{
		cur = cur->next;
	}
	cur->next = newnode;
}


// 查找(顺序查找) 找到了,返回所在结点地址,没有找到返回 NULL
Node* FindLinList(pNode* pn, DataType d)
{
	assert(pn);
	Node* cur;
	for (cur = *pn; cur != NULL; cur = cur->next)
	{
		if (cur->data == d)
		{
			return cur;
		}
	}
	return NULL;
}

一、从尾到头打印单链表

  • 递归

void TailPrintR(Node* pfirst)
{
	if (pfirst == NULL)
	{
		return;

	}

	TailPrintR(pfirst->next);
	printf("%d ", pfirst->data);
}
  • 非递归
void TailPrint(Node* pfirst)
{
	Node* cur = pfirst;
	Node* last = NULL;

	while (last != pfirst)
	{
		cur = pfirst;
		while (cur->next != last)
		{
			cur = cur->next;
		}

		printf("%d ", cur->data);
		last = cur;
	}
}

 

二、删除一个无头单链表的非尾节点(不能遍历链表)

void RemoveNoHeadNotTail(Node* Del)
{
	assert(Del->next != NULL);
	Node* next = Del->next;
	Del->data = next->data;
	Del->next = next->next;
	free(next);
}

三、在无头单链表的一个节点前插入一个节点(不能遍历链表)

void BeforeNode(Node* node, DataType d)
{
	assert(node);
	Node* newnode = (Node*)malloc(sizeof(Node));
	newnode->data = node->data;
	newnode->next = node->next;

	node->data = d;
	node->next = newnode;
}

四、单链表实现约瑟夫环

void JosephCircle(Node* first)
{
	// 构成环
	Node *cur = first;
	while (cur->next != NULL)
	{
		cur = cur->next;
	}
	cur->next = first;

	cur = first;
	while (cur->next != cur)
	{
		cur = cur->next;
		Node* Del = cur->next;
		cur->next = Del->next;
		free(Del);
		cur = cur->next;

	}

	printf("%d\n", cur->data);
}

五、逆置/反转单链表

void Reverse1(Node* first)
{
	if (first == NULL || first->next == NULL)
	{
		return;
	}

	Node* p1 = first;
	Node* p2 = first->next;
	Node* p3 = first->next->next;
	while (p2 != NULL)
	{
		p2->next = p1;
		p1 = p2;
		p2 = p3;
		if (p3 != NULL)
		{
			p3 = p3->next;
		}
	}
	first->next = NULL;

	PrintLinList(p1);
}
void Reverse2(Node* first)
{
	assert(first);
	Node* result = NULL;
	Node* cur = first;
	Node* node;
	while (cur != NULL)
	{
		node = cur;
		cur = cur->next;

		node->next = result;
		result = node;
	}
	PrintLinList(result);
}

六、单链表排序(冒泡排序&快速排序)

void BubbleSort(Node* first)
{
	assert(first);
	Node* tail = NULL;
	Node* cur = first;
	int flg = 1;//有序
	while (cur != tail)
	{
		while (cur->next != tail)
		{
			if (cur->data > cur->next->data)
			{
				DataType tmp = cur->data;
				cur->data = cur->next->data;
				cur->next->data = tmp;
				flg = 0;
			}
			cur = cur->next;
		}
		if (flg == 1)
		{
			return;
		}
		tail = cur;
		cur = first;
	}

}

七、合并两个有序单链表,合并后依然有序

void Merge(Node *list1, Node *list2)
{
	Node* result = NULL;
	Node* tail = NULL;	// result这个链表中的最后一个结点

	Node* cur1 = list1;
	Node* cur2 = list2;
	Node* node;

	while (cur1->next != NULL&&cur2->next != NULL)
	{
		if (cur1->data <= cur2->data)
		{
			node = cur1;//需要插入的节点;
			cur1 = cur1->next;

		}
		else
		{
			node = cur2;
			cur2 = cur2->next;

		}

		//把找到的node插入result
		if (tail == NULL)
		{
			result = node;
		}
		else
		{
			tail->next = node;
		}
		node->next = NULL;
		//node成为最后一个节点;
		tail = node;
	}
	if (cur1->next == NULL)
	{
		tail->next = cur2;
	}
	if (cur2->next == NULL)
	{
		tail->next = cur1;
	}

	PrintLinList(result);
}

八、查找链表的中间节点,要求只能遍历一次

void FindMidNode(Node* first)
{
	Node* fast = first;
	Node* slow = first;

	while (1)
	{
		fast = fast->next;
		if (fast == NULL)
		{
			break;
		}
		fast = fast->next;
		if (fast == NULL)
		{
			break;
		}
		slow = slow->next;
	}

	printf("%d\n", slow->data);
}

九、求两个已排序单链表中相同的数据

void UnionSet(Node* last1, Node* last2)
{
	Node* cur1 = last1;
	Node* cur2 = last2;

	while (cur1 != NULL&&cur2 != NULL)
	{
		if (cur1->data == cur2->data)
		{
			printf("%d ", cur1->data);
			Node* Front1 = cur1;
			Node* Front2 = cur2;
			cur1 = cur1->next;
			cur2 = cur2->next;

			//处理重复问题:如:1 1 2 3     1 1 3 4
			if (Front1->data == cur1->data&&Front2->data == cur2->data)
			{
				cur1 = cur1->next;
				cur2 = cur2->next;
			}
		}
		else if (cur1->data < cur2->data)
		{
			cur1 = cur1->next;
		}
		else
		{
			cur2 = cur2->next;
		}

	}
	printf("\n");
}

十、查找链表倒数第k个节点,要求只能遍历一遍

void TheLastK(Node* first, int k)
{
	assert(first);
	assert(k > 0);
	Node* forward = first;
	Node* backward = first;
	Node* Front = first;
	//forward先走(k-1)步
	while (--k)
	{
		forward = forward->next;
	}

	while (forward->next != NULL)
	{
		Front = backward;
		backward = backward->next;
		forward = forward->next;
	}
	//打印倒数第k个
	printf("%d\n", backward->data);
	//删除倒数第k个
	Front->next = backward->next;
	free(backward);
	PrintLinList(first);

}

十一、判断两个链表是否相交,若相交,求焦点(不带环)

int GetLength(Node* first)
{
	int count = 0;
	Node* cur = first;
	while (cur!=NULL)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

Node* Intersect(Node* last1, Node* last2)
{
	Node* cur1 = last1;
	Node* cur2 = last2;
	while (cur1->next!=NULL)
	{
		cur1 = cur1->next;
	}
	while (cur2->next != NULL)
	{
		cur2 = cur2->next;
	}
	if (cur1!=cur2)
	{
		printf("不相交\n");
		return;
	}


	//一定有焦点
	int len1 = GetLength(last1);
	int len2 = GetLength(last2);
	int lenD = 0;
	Node* forward = NULL;
	Node* backward = NULL;
	if (len1 <= len2)
	{
		forward = last2;
		backward = last1;
		lenD = len2 - len1;
	}
	else
	{
		forward = last1;
		backward = last2;
		lenD = len1 - len2;
	}

	while (lenD--)
	{
		forward = forward->next;
	}

	while (forward != backward)
	{
		forward = forward->next;
		backward = backward->next;
	}
	return forward;
}

十二、判断单链表是否代换?若带环,求环的长度?求环的入口点?

void IsNoCircle(Node* first)
{
	Node* fast = first;
	Node* slow = first;
	while (fast->next!=NULL)
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast==slow)
		{
			printf("带环\n");

			return;
		}
	}
	printf("不带环\n");
}


//带环
int CircleLength(Node* first)
{
	Node* fast = first;
	Node* slow = first;
	fast = fast->next;
	slow = slow->next;
	int count = 1;
	while (fast!=slow)
	{
		fast = fast->next;
		slow = slow->next;
		count++;
	}
	return count;
}

//入口
Node* Entry(Node* first)
{
	Node* fast = first;
	Node* slow = first;
	fast = fast->next;
	slow = slow->next;
	while (fast!=slow)
	{
		fast = fast->next;
		slow = slow->next;
	}
	Node* node = first;
	while (node!=slow)
	{
		node = node->next;
		slow = slow->next;
	}
	return node;
}

十三、复杂链表的复制

typedef struct ComplexNode
{
	struct ComplexNode* next;
	struct ComplexNode* random;
	DataType data;
}CN;


CN * CreateNode(int d)
{
	CN *node = (CN *)malloc(sizeof(CN));
	node->data = d;
	node->random = node->next = NULL;

	return node;
}


CN* InitComplexList()
{
	CN* n1 = CreateNode(1);
	CN* n2 = CreateNode(2);
	CN* n3 = CreateNode(3);
	CN* n4 = CreateNode(4);
	n1->next = n2; n2->next = n3; n3->next = n4;
	n1->random = n4; n2->random = n1; n3->random = n3;

	return n1;
}



void CopyComplexList(CN* list)
{
	// 复制链表每个结点,让新的结点跟在老的结点后边
	CN* cur = list;
	CN* newnode = NULL;
	// cur 只遍历老的结点
	while (cur != NULL)
	{
		newnode = CreateNode(cur->data);
		newnode->next = cur->next;
		cur->next = newnode;

		cur = newnode->next;
	}

//复制random
	cur = list;
	while (cur!=NULL)
	{
		newnode = cur->next;
		if (cur->random!=NULL)
		{
			newnode->random = cur->random->next;
		}
		cur = newnode->next;
	}

	cur = list;
	CN *Next, *newNext;
	CN *result = list->next;
	while (cur!=NULL)
	{
		newnode = cur->next;
		Next = newnode->next;
		if (Next!=NULL)
		{
			newNext = Next->next;
		}
		else
		{
			newNext = NULL;
		}
		cur->next = Next;
		newnode->next = newNext;

		cur = cur->next;

	}
	printf("复制成功\n");

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值