C语言实现单链表面试题--基础篇

顺序表和链表的优缺点

顺序表

优点:顺序表是将数据存储在一段连续的内存中,可以通过下标随机访问,效率高。

缺点:插入和删除数据时效率很低,移动数据时需要表里。增容时需要重新开辟内存,有可能造成浪费。

链表

优点:链表在程序运行时动态分配内存,插入和删除速度快。

缺点:不支持随机访问,查找时需要遍历链表。

从各自的优缺点根据使用场景选择。频繁插入、删除使用链表。反之,频繁查找选择顺序表。

void Print_TailToHead(ListNode *pList)//从尾到头打印
{
	if(!pList)
	{
		printf("NULL");
		return;
	}
	Print_TailToHead(pList->next);
	printf("->%d", pList->data);

}

void Erase_Notail(ListNode *pos)//删除一个无头单链表的非尾节点
{
	ListNode *tmp = pos->next;
	assert((pos) && (pos->next));

	pos->data = tmp->data;
	pos->next = tmp->next;
	free(tmp);
}

void Insert_Nohead(ListNode *pos, DataType x)//在无头单链表的一个节点前插入一个节点
{
	ListNode *tmp = CreatNode(pos->data);
	assert(pos);

	pos->data = x;
	tmp->next = pos->next;
	pos->next = tmp;
}

DataType Josephus(ListNode *pList, int k)//单链表实现约瑟夫环
{
	ListNode *tmp = pList;

	while(tmp->next)
	{
		tmp = tmp->next;
	}
	tmp->next = pList;

	while(pList->next != pList)
	{
		int ret = k;
		while(--ret)
		{
			pList = pList->next;
		}
		tmp = pList->next;
		pList->data = tmp->data;
		pList->next = tmp->next;
		free(tmp);
	}
	return pList->data;
}

void Severse(ListNode **ppList)//逆置/反转单链表
{
	ListNode *Now = NULL;

	if((*ppList == NULL)||((*ppList)->next == NULL))
	{
		return;
	}

	while((*ppList)->next)
	{
		ListNode *tmp = (*ppList)->next;
		(*ppList)->next = Now;
		Now = *ppList;
		*ppList = tmp;
	}
	(*ppList)->next = Now;
}

void Bubble_sort(ListNode *ppList)//单链表排序(冒泡排序&快速排序)
{
	ListNode *p1 = ppList;
	ListNode *tmp = NULL;

	if((ppList == NULL) || (ppList->next == NULL))
	{
		return;
	}

	while(p1 != tmp)
	{
		ListNode *pList2 = ppList->next;//定义在这里为了防止ppList为空

		while(pList2 != tmp)
		{
			if((p1->data)>(pList2->data))
			{
				DataType ret = p1->data;
				p1->data = pList2->data;
				pList2->data = ret;
			}
			p1 = p1->next;
			pList2 = pList2->next;
		}
		tmp = p1;
		p1 = ppList;
		pList2 = ppList->next;
	}
}

ListNode* Combine(ListNode *pList1, ListNode *pList2)//合并两个有序链表,合并后依然有序
{
	ListNode *head = NULL;
	ListNode *NowList = NULL;

	if(pList1 == NULL)
		return pList2;
	if(pList2 == NULL)
		return pList1;

	if(pList1->data < pList2->data)
	{
		head = pList1;
		pList1 = pList1->next;
	}
	else
	{
		head = pList2;
		pList2 = pList2->next;
	}

	NowList = head;
	while((pList1!=NULL) && (pList2!=NULL))
	{
		if((pList1->data) < (pList2->data))
		{
			NowList->next = pList1;
			pList1 = pList1->next;
			NowList = NowList->next;
		}
		else
		{
			NowList->next = pList2;
			pList2 = pList2->next;
			NowList = NowList->next;
		}
	}
	if(pList1 == NULL)
		NowList->next = pList2;
	else
		NowList->next = pList1;

	return head;
}

ListNode* Find_MidNode(ListNode *pList)//查找单链表的中间节点,要求只能遍历一次链表
{
	ListNode *fast = pList;//这里当然也可以时pList,但返回值有区别,不信可以验证下
	ListNode *slow = pList;
	assert(pList);

	if((pList == NULL) || (pList->next == NULL))
		return pList;

	while((fast->next != NULL) && (fast->next->next != NULL))
	{
		fast = fast->next->next;
		slow = slow->next;
	}
	return slow;//当链表个数为偶数时:slow返回中间两个节点的前一个节点,slow->next返回中间节点的后一个节点
}

ListNode* Find_Rec_k_Node(ListNode *pList, int k)//查找单链表的倒数第k个节点,要求只能遍历一次链表
{
	ListNode *fast = pList;
	ListNode *slow = pList;
	assert(pList && k);

	while(--k)
	{
		fast = fast->next;
		if(fast == NULL)
			return NULL;
	}

	while(fast->next != NULL)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return slow;
}

关于链表的所有测试用例

#include "List.h"

void test1()//测试PushBack/PopBack
{
	ListNode *List = NULL;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PrintList(List);
	Print_TailToHead(List);
	printf("\n");

	PopBack(&List);
	PopBack(&List);
	PrintList(List);

	PopBack(&List);
	PopBack(&List);
	PrintList(List);
}

void test2()//测试PushFront/PopFront
{
	ListNode *List = NULL;
	PushFront(&List, 4);
	PushFront(&List, 3);
	PushFront(&List, 2);
	PushFront(&List, 1);
	PrintList(List);

	PopFront(&List);
	PopFront(&List);
	PrintList(List);	
	
	PopFront(&List);
	PopFront(&List);
	PrintList(List);
}

void test3()//测试Insert/Erase
{
	ListNode *List = NULL;
	ListNode *ret = NULL;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PrintList(List);

	ret = Find(List, 4);
	Insert(&List, ret, 0);
	PrintList(List);

	ret = Find(List, 4);
	Erase(&List, ret);
	PrintList(List);
}

void test4()//测试Erase_Notail/Insert_Nohead
{
	ListNode *List = NULL;
	ListNode *pos = NULL;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PrintList(List);

	pos = Find(List, 2);
	Erase_Notail(pos);
	PrintList(List);

	pos = Find(List, 3);
	Insert_Nohead(pos, 2);
	PrintList(List);
}

void test5()//测试Josephus
{
	ListNode *List = NULL;
	DataType tmp = 0;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PrintList(List);

	tmp = Josephus(List, 3);
	printf("%d\n", tmp);
}

void test6()//测试Severse/Bubble_sort
{
	ListNode *List = NULL;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PrintList(List);

	Severse(&List);
	PrintList(List);

	Bubble_sort(List);
	PrintList(List);
}

void test7()//测试Combine
{
	ListNode *List1 = NULL;
	ListNode *List2 = NULL;
	ListNode *Now = NULL;

	PushBack(&List1, 3);
	PushBack(&List1, 3);
	PushBack(&List1, 6);

	PushBack(&List2, 1);
	PushBack(&List2, 2);
	PushBack(&List2, 2);
	PushBack(&List2, 7);
	
	Now = Combine(List1, List2);
	PrintList(Now);
}

void test8()//测试Find_MidNode
{
	ListNode *List = NULL;
	ListNode *ret = NULL;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PushBack(&List, 5);
	PushBack(&List, 6);
	ret = Find_MidNode(List);
	printf("%d\n", ret->data);
}

void test9()//测试Find_Rec_k_Node
{
	ListNode *List = NULL;
	ListNode *ret = NULL;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PushBack(&List, 5);
	PushBack(&List, 6);
	ret = Find_Rec_k_Node(List, 3);
	printf("%d\n", ret->data);
}

void test10()//测试judge_band/judge_band_length/judge_band
{
	ListNode *List = NULL;
	ListNode *tmp = NULL;
	ListNode *tail = NULL;

	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PushBack(&List, 5);
	PushBack(&List, 6);
	
	tmp = Find(List, 3);
	tail = Find(List, 6);
	tail->next = tmp;

	printf("%p\n", judge_band(List));
	printf("%d\n", judge_band_length(List));
	printf("%p\n", Find(List, 3));
}

void test11()//测试judge_intersect/judge_junction
{
	ListNode *List1 = NULL;
	ListNode *List2 = NULL;
	ListNode *p1 = NULL;
	ListNode *p2 = NULL;

	PushBack(&List1, 1);
	PushBack(&List1, 2);
	PushBack(&List1, 3);
	PushBack(&List1, 4);
	PushBack(&List1, 5);
	PushBack(&List1, 6);
	p1 = Find(List1, 3);

	PushBack(&List2, 1);
	PushBack(&List2, 2);
	PushBack(&List2, 3);
	PushBack(&List2, 4);
	p2 = Find(List2, 4);
	p2->next = p1;

	printf("%p\n", judge_intersect(List1, List2));
	//printf("%p\n", judge_junction(List1, List2));
	printf("%p\n", Find(List1, 3));
}

void test12()//测试judge_band_intersect
{
	ListNode *List1 = NULL;
	ListNode *List2 = NULL;
	ListNode *p1 = NULL;
	ListNode *p2 = NULL;

	PushBack(&List1, 1);
	PushBack(&List1, 2);
	PushBack(&List1, 3);
	PushBack(&List1, 4);
	PushBack(&List1, 5);
	PushBack(&List1, 6);
	p1 = Find(List1, 3);
	p2 = Find(List1, 6);
	p2->next = p1;

	PushBack(&List2, 1);
	PushBack(&List2, 2);
	PushBack(&List2, 3);
	PushBack(&List2, 4);
	PushBack(&List2, 5);
	PushBack(&List2, 6);

	//测试都带环但不相交
	//p2 = Find(List2, 6);
	//p1 = Find(List2, 3);
	//p2->next = p1;
	//测试都带环且相交
	p2 = Find(List2, 6);
	p1 = Find(List1, 5);
	p2->next = p1;


	printf("%p\n", judge_band_intersect(List1, List2));

	printf("%p\n", judge_band(List1));
	printf("%p\n", judge_band(List2));

	printf("%p\n", Find(List1, 3));
	printf("%p\n", Find(List2, 3));
}

void test13()//测试cpye_dif_List
{
	ListNode *List = NULL;
	ListNode *NewList = NULL;

	ListNode *p1 = NULL;
	ListNode *p2 = NULL;
	ListNode *p3 = NULL;
	ListNode *p4 = NULL;
	ListNode *p5 = NULL;
	PushBack(&List, 1);
	PushBack(&List, 2);
	PushBack(&List, 3);
	PushBack(&List, 4);
	PushBack(&List, 5);

	p1 = Find(List, 1);
	p2 = Find(List, 2);
	p3 = Find(List, 3);
	p4 = Find(List, 4);
	p5 = Find(List, 5);

	p1->random = p3;
	p2->random = p1;
	p3->random = p3;
	p4->random = p2;
	p5->random = p4;

	NewList = cpye_dif_List(List);
	PrintList(List);
	PrintList(NewList);
}

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	//test6();
	//test7();
	//test8();
	//test9();
	//test10();
	//test11();
	//test12();
	//test13();

	return 0;
}


代码是测试过得,如有不对不完善之处,欢迎留言指正.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值