链表经典题目合集(c语言版)

链表经典题目合集(c语言版)

链表作为数据结构中较为热门的类型,一直是各大公司笔试面试常考类型,同时链表也有很多经典题目,可以帮助初学者更好的理解链表。
1.从尾到头打印链表

先遍历链表,遍历的同时将链表的值头插进一个新的链表,在打印新的链表即可。

void SLitsPrintTailToHead(SListNode* pHead)
{
	SListNode* _new, *ptr;
	_new = NULL;
	ptr = pHead;
	while (ptr)
	{
		SListPushFront(&_new, ptr->data);
		ptr = ptr->next;
	}
	while (_new)
	{
		printf("%d ", _new->data);
		_new = _new->next;
	}
}

2.删除一个无头单链表的非尾节点(不能遍历链表)
假设删除的是pos节点,我们可以将pos的下一个节点的数据存入pos节点,在删除pos节点的下一个节点即可。
void SListDelNonTailNode(SListNode* pos)
{
	SListNode* Ppos;
	Ppos = NULL;
	Ppos = pos->next;
	pos->data = Ppos->data;
	pos->next = Ppos->next;
	free(Ppos);
}

3. 在无头单链表的一个节点前插入一个节点(不能遍历链表)
假设我们需要在pos前插入一个节点,我们可以先在pos后插入一个与pos数据一样的节点,在将pos的数据改为给的值。
void SListInsertFrontNode(SListNode* pos, DataType x)
{
	SListNode* _new;
	_new = NULL;
	_new = BuySListNode(pos->data);
	_new->next = pos->next;
	pos->next = _new;
	pos->data = x;
}

4. 单链表实现约瑟夫环(JosephCircle)
约瑟夫环 是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依 规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后 结果+1即为原问题的解。
先不断迭代找到尾节点,让尾节点的next指针指向头节点,这样形成了一个环,接着进入循环,循环的结束条件为只剩一个节点。不断地迭代k次然后删除当前节点。
SListNode* SListJosephCircle(SListNode* pHead, int k)
{
	SListNode* str, *tail;
	int i = 0;
	str = pHead;
	tail = pHead;
	while (tail->next)
	{
		tail = tail->next;
	}
	tail->next = pHead;
	while (str->next!=str)
	{
		for (;i < k;++i)
		{
			str = str->next;
		}
		str->data = str->next->data;
		str->next = str->next->next;
		free(str->next);
	}
	return str;
}

5. 逆置/反转单链表
遍历链表,同时将数据头插入链表,新的链表为反转链表。
SListNode* SListReverse(SListNode* list)
{
	SListNode* _new, *str;
	_new = NULL;
	str = list;
	while (str)
	{
		SListPushFront(&_new, str->data);
		str = str->next;
	}
	return _new;
}
6.单链表冒泡排序
void SListBubbleSort(SListNode* list)
{
	int i, j,count;
	count = 0;
	int mid;
	SListNode* str,*ptri,*ptrj;
	str = list;
	while (str)
	{
		str = str->next;
		count++;
	}
	for (i = 0;i < count-1;i++)
	{
		ptri = list;
		ptri = ptri->next;
		for (j = 0;j < i-1;j++)
		{
			ptrj = list;
			ptrj = ptrj->next;
			if (ptri->data > ptrj->data)
			{
				mid = ptri->data;
				ptri->data = ptrj->data;
				ptrj->data = mid;
			}
		}
	}
}

7. 合并两个有序链表,合并后依然有序
给两个指针分别指向两个有序链表,两个链表所指向的数据进行比大小,小的插入新链表并且指针向后走,进行下一次比较,当两个指针都走完时结束。

SListNode* SListMerge(SListNode* list1, SListNode* list2)
{
	SListNode* str1, *str2,*_new;
	str1 = list1;
	str2 = list2;
	_new = NULL;
	while (str1&&str2)
	{
		if (str1->data > str2->data)
		{
			SListPushBack(&_new,str2->data);
			str2 = str2->next;
		}
		if (str1->data < str2->data)
		{
			SListPushBack(&_new, str1->data);
			str1 = str1->next;
		}
		else
		{
			SListPushBack(&_new, str2->data);
		}
	}
	return _new;
}

8. 查找单链表的中间节点,要求只能遍历一次链表
给两个指针,第一个指针走一步时第二个指针走两步,当快指针走完时慢指针走到中间节点。
SListNode* SListFindMidNode(SListNode* list)
{
	SListNode* fast, *slow;
	fast = list;
	slow = list;
	while (fast->next)
	{
		fast = fast->next;
		if (fast->next == NULL)
		{
			break;
		}
		fast = fast->next;
		slow = slow->next;
	}
	return slow;
}

9. 查找单链表的倒数第k个节点,要求只能遍历一次链表
同样定义两个指针,快指针先走k步慢指针开始走,当快指针走完时慢指针走到倒数第K个节点。
SListNode* SListFindTailKNode(SListNode* list, size_t k)
{
	SListNode* fast, *slow;
	fast = list;
	slow = list;
	int i;
	for (i = 0;i < k;i++)
	{
		fast = fast->next;
	}
	while (fast)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return slow;
}

扫描二维码关注公众号,回复: 53180 查看本文章
10.构造一个带环链表
找到环入口的节点,让尾节点指向入口节点。
SListNode* SListIsCycle(SListNode* list)
{
	SListNode* str,*ptr;
	str = list;
	ptr = SListFind(list, 0);
	while (str)
	{
		str = str->next;
	}
	str->next = ptr;
	return ptr;
}

11.求环的长度
定义两个快慢指针,快指针走两步慢指针走一步,当他们在环里相遇时结束。再让他们继续走,第二次相遇时快指针一定比慢指针快了环的长度步。
int SListCycleLen(SListNode* meetNode)
{
	int len,count1,count2;
	SListNode*fast, *slow;
	fast = meetNode->next;
	slow = meetNode;
	int count=1;
	while (fast!=slow)
	{
		fast = fast->next->next;
		slow = slow->next;
	}
	slow - slow->next;
	while (slow != fast)
	{
		slow = slow->next;
		count++;
	}
	return count;
}

猜你喜欢

转载自blog.csdn.net/qq9116136/article/details/80056633