【c语言】链表的实现、链表部分面试题的解答

一、链表与数组的比较:

(1)数组:

数组优点:a.可以利用偏移地址来访问元素,效率高,为O(1);

                    b.可以使用折半查找元素,效率较高;

数组缺点:a.空间连续,存储效率低;

                   b.插入和删除元素效率比较低;

(2)链表:

链表优点:a.插入和删除元素不需要移动其余元素,效率高,为O(1);

                   b.不要求连续空间,空间利用效率高;

链表缺点:a.不提高随机访问元素的机制;

                   b.查找元素和搜索元素的效率低,最快情况下为O(1),平常情况为O(N);

二、链表与数组在空间中储存图示:

(1)数组的储存方式:是连续存放的


(2)链表的储存方式:不是连续存放的


三、代码区:

    (链表的实现与链表的面试题的实现

头文件(#LinkList.h)

#ifndef _LINK_H__
#define _LINK_H__

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>

typedef int Datatype;

typedef struct Node
{
	Datatype data;
	struct Node*next;  //指向下一个地址的指针
	//struct Node*last;  //指向上一个地址的指针
	
}Node, *pNode;

void InitLinkList(pNode *head);    //初始化函数
void PushFront(pNode *head,Datatype d);  //头插
void PopFront(pNode*head);       //头删
void PushBack(pNode *head, Datatype d);  //尾插
void PopBack(pNode*head);            //尾删
void Reverse(pNode*head);            //逆序
void Insert(pNode*head,Datatype d,int pos);   //指定位置插入数据
void DelNotTail(pNode pos);    //删除无头的不为结尾的任意一个节点
pNode Find(pNode head,Datatype d);   //查找函数
pNode FindMidNode(pNode plist);   //找中间节点的位置
pNode CheckCycle(pNode plist);    //检测是否带环
int GetCircleLength(pNode meet);   //求环的长度
pNode GetCircleEntryNode(pNode meet, pNode plist);  //获取环的进入点
pNode CheckCross(pNode p1, pNode p2);  //两条链的交点
void JosephCycle(pNode plist, int k);     //约瑟夫环
void DelKNode(pNode plist, int k);   //删除倒数第k个节点
void SortList(pNode head);      //冒泡排序
void Reverseshow(pNode head);  //逆序打印
pNode Merge(pNode plist1, pNode plist2);    //两条有序链的合并,合并之后依然有序
void Display(pNode head);          //显示函数
void DestroyList(pNode*head);      //释放空间

#endif //

函数(LinkList.c)

#include"Linklist.h"

void InitLinkList(pNode *head)    //初始化函数
{
	*head = NULL;
}
void PushFront(pNode*head, Datatype d)   //头部插入数据函数
{
	assert(head);

	pNode p = malloc(sizeof(Node));
	memset(p, 0, sizeof(Node));
	p->data = d;
	p->next = NULL;
	
	p->next = *head;
	*head = p;
}
void PopFront(pNode*head)     //头部删除数据函数
{
	pNode pur = *head;
	if (pur == NULL)
		return;
	else
	{
		*head = pur->next;
		free(pur);
	}
}

void PushBack(pNode *head,Datatype d)   //尾部插入数据函数
{
	pNode pur = *head;
	pNode p = malloc(sizeof(Node));
	memset(p, 0, sizeof(Node));
	p->data = d;
	p->next = NULL;
	if (pur == NULL)
	{
		*head = p;
	}
	else
	{
		while (pur->next != NULL)
		{
			pur = pur->next;
		}
		pur->next = p;
	}
}
void PopBack(pNode *head)      //尾部删除数据函数
{
	assert(head);
	pNode pur = NULL;
	pNode cur = *head;
	if (*head == NULL)
		return;
	while (cur->next != NULL)
	{
		pur = cur;
		cur = cur->next;
	}
	if (pur!= NULL)
	{
		pur->next = NULL;
		free(cur);
	}
	else
	{
		free(cur);
		*head = NULL;
	}
}

void Insert(pNode*head,Datatype d,int pos)    //指定位置插入函数
{
	pNode pur = NULL;
	pNode cur = *head;
	pNode p = malloc(sizeof(Node));
	p->data = d;
	p->next = NULL;
	if (*head == NULL)
	{
		*head = p;
		return;
	}
	if (pos == 1)
	{
		p->next = *head;
		*head = p;
	}
	else
	{
		while (pos - 1)
		{
			pur = cur;
			cur = cur->next;
			pos--;
		}
		p->next = cur;
		pur->next = p;
	}
}

void Reverse(pNode*head)         //逆序函数
{
	pNode cur = *head;
	pNode newhead = NULL;
	pNode tail = NULL;
	if (cur == NULL || cur->next == NULL)
		return;
	while (cur!=NULL)
	{
		newhead = cur;
		cur = cur->next;
		newhead->next = tail;
		tail = newhead;
	}
	*head = newhead;
}

void Reverseshow(pNode head)       //逆序打印函数
{
	pNode pur = head;
	if (pur == NULL)
		return;
	Reverseshow(pur->next);
	printf("%d-->", pur->data);
}

void DelNotTail(pNode pos)       //删除无头的非尾节点
{
	if (pos == NULL)
		return;
	if (pos->next == NULL)
		free(pos);
	else
	{
		pNode cur = NULL;
		pos->data = pos->next->data;
		cur = pos->next;
		pos->next = cur->next;
		free(cur);
	}
}

pNode Find(pNode head,Datatype d)    //查找函数
{
	pNode cur = head;
	while (cur!=NULL)
	{
		if (cur->data == d)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

pNode FindMidNode(pNode plist)       //查找中间节点函数
{
	pNode cur = plist;
	pNode fast = plist;
	pNode slow = plist;
	if (cur == NULL || cur->next == NULL)
		return cur;
	while (fast->next!=NULL)
	{
		fast = fast->next->next;
		slow = slow->next;
	}
	return slow;
}

pNode CheckCycle(pNode plist)       //判断链表是否带环
{
	pNode cur = plist;
	pNode fast = plist->next->next;
	pNode slow = plist->next;
	
	while (fast->next!=NULL)
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast == slow)
		{
			return fast;
		}
	}
	return NULL;
}

int GetCircleLength(pNode meet)      //测量环的长度
{
	pNode cur = meet;
	pNode ret = meet->next;
	int k = 0;
	while (1)
	{
		k++;
		if (cur == ret)
			return k;
		ret = ret->next;
	}
}

pNode GetCircleEntryNode(pNode meet, pNode plist)   //查找环的进入点
{
	pNode fast = plist;
	pNode slow = plist;
	int len=GetCircleLength(meet);
	while (len)
	{
		fast = fast->next;
		len--;
	}
	while (fast != slow)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return slow;
}

pNode GetNode(pNode plist1, pNode plist2,int k)  //CheckCross函数的子函数
{
	pNode fast = plist1;
	pNode slow = plist2;
	int len = k;
	while (len)
	{
		fast = fast->next;
		len--;
	}
	while (fast != slow)
	{
		fast = fast->next;
		slow = slow->next;
	}
	return slow;
}
pNode CheckCross(pNode p1, pNode p2)     //判断两条链是否相交,若相交返回交点位置
{
	pNode plist1 = p1;
	pNode plist2 = p2;
	int count1 = 0, count2 = 0;
	int k = 0;   //两条链的长度差
	while (plist1!=NULL)
	{
		count1++;
		plist1 = plist1->next;
	}
	while (plist2 != NULL)
	{
		count2++;
		plist2 = plist2->next;
	}
	if (plist1 != plist2)
		return NULL;
	if ((count1 - count2) > 0)
	{
		k = count1 - count2;
		return GetNode(p1, p2, k);
	}
	else
	{
		k = count2 - count1;
		return GetNode(p1, p2, k);
	}
}

void JosephCycle(pNode plist, int k)     //约瑟夫环
{
	pNode cur = plist;
	while (cur!=cur->next)
	{
		pNode pur = NULL;
		int count = 2;
		while (count!=k)
		{
			count++;
			cur = cur->next;
		}
		pur = cur->next;
		cur->next = pur->next;
		printf("%d ", pur->data);
		free(pur);
		cur = cur->next;
	}
	printf("%d ", cur->data);
}

void DelKNode(pNode plist, int k)    //删除倒数第k个节点
{
	pNode ret = plist;
	pNode fast = plist;
	pNode slow = plist;
	pNode cur = NULL;
	int len = 0;
	while (ret!=NULL)
	{
		ret = ret->next;
		len++;
	}
	if (k == 0)
	{
		return;
	}
	    k = k%len;
	if (k ==0)
	{
		plist->data = plist->next->data;
		cur = plist->next;
		plist->next = cur->next;
		free(cur);
		return;
	}
	while (fast->next!=NULL)
	{
		if (k> 0)
		{
			fast = fast->next;
			k--;
		}
		else
		{
			fast = fast->next;
			slow = slow->next;
		}
	}
	cur = slow->next;
	slow->next = cur->next;
	free(cur);
}

pNode Merge(pNode plist1, pNode plist2)   //合并两条有序链表
{
	pNode ret1 = plist1;
	pNode ret2 = plist2;
	while (plist1->next != NULL)
	{
		plist1 = plist1->next;
	}
	plist1->next = ret2;
	SortList(ret1);
	return ret1;
}

void SortList(pNode head)    //排序
{
	pNode cur = head;
	pNode tail = NULL;
	pNode ret = NULL;
	if (head == NULL)
		return;
	while (cur->next!=tail)
	{
		while (cur->next!= tail)
		{
			if ((cur->data) > (cur->next->data))
			{
				Datatype ret = cur->data;
				cur->data = cur->next->data;
				cur->next->data = ret;
			}
			cur = cur->next;
			ret = cur;
		}
		tail = ret;
		cur = head;
	}
}

void Display(pNode head)      //显示函数
{
	pNode pur = head;
	while (pur != NULL)
	{
		printf("%d-->", pur->data);
		pur = pur->next;
	}
	printf("over\n");
}
void DestroyList(pNode*head)     //释放空间函数
{
	pNode cur = NULL;
	while (*head!=NULL)
	{
		cur = *head;
		*head = cur->next;
		free(cur);
	}
	*head = NULL;
}

测试函数(test.c)

#include"Linklist.h"

void test1()
{
	pNode head = NULL;  //结构体类型的指针
	InitLinkList(&head);
	PushBack(&head, 1);
	PushBack(&head, 2);
	PushBack(&head, 3);
	PushBack(&head, 4);
	Display(head);
	PopBack(&head);
	Display(head);
	PopBack(&head);
	Display(head);
	PopBack(&head);
	Display(head);
	PopBack(&head);
	Display(head);
	PopBack(&head);
	Display(head);
	DestroyList(&head);
}

void test2()
{
	pNode head = NULL;
	InitLinkList(&head);
	PushFront(&head,1);
	PushFront(&head,2);
	PushFront(&head,3);
	PushFront(&head,4);
	Display(head);
	PopFront(&head);
	Display(head);
	PopFront(&head);
	Display(head);
	PopFront(&head);
	Display(head);
	PopFront(&head);
	Display(head);
	PopFront(&head);
	Display(head);
	DestroyList(&head);
}

void test3()
{
	pNode head = NULL;
	InitLinkList(&head);
	PushFront(&head, 1);
	PushFront(&head, 2);
	PushFront(&head, 3);
	PushFront(&head, 4);
	Display(head);
	Insert(&head, 9, 2);
	Display(head);
	DestroyList(&head);
}

void test4()    //逆序
{
	pNode head = NULL;
	InitLinkList(&head);
	PushFront(&head, 1);
	PushFront(&head, 2);
	PushFront(&head, 3);
	PushFront(&head, 4);
	PushFront(&head, 5);
	PushFront(&head, 6);
	Display(head);
	Reverse(&head);
	Display(head);
	DestroyList(&head);
}
test5()
{
	pNode head = NULL;
	InitLinkList(&head);
	PushFront(&head, 1);
	PushFront(&head, 2);
	PushFront(&head, 3);
	PushFront(&head, 4);
	PushFront(&head, 5);
	Display(head);          //显示
	Reverseshow(head);      //逆序显示
	DestroyList(&head);
}

test6()
{
	pNode head = NULL;
	pNode pos = NULL;
	InitLinkList(&head);
	PushFront(&head, 1);
	PushFront(&head, 2);
	PushFront(&head, 3);
	PushFront(&head, 4);
	PushFront(&head, 5);
	Display(head);
	pos=Find(head, 2);
	if (pos == NULL)
		printf("\n");
	else
	printf("%d\n", pos->data);
	DelNotTail(pos);
	Display(head);
	DestroyList(&head);
}

test7()
{
	pNode head = NULL;
	InitLinkList(&head);
	PushFront(&head, 1);
	PushFront(&head, 5);
	PushFront(&head, 3);
	PushFront(&head, 2);
	PushFront(&head, 4);
	Display(head);
	SortList(head);
	Display(head);
	DestroyList(&head);
}

void test8()
{
	pNode head = NULL;
	pNode ret = NULL;
	InitLinkList(&head);
	PushFront(&head, 1);
	PushFront(&head, 5);
	PushFront(&head, 3);
	PushFront(&head, 2);
	PushFront(&head, 4);
	Display(head);
	ret=FindMidNode(head);
	if (ret!=NULL)
	printf("%d\n", ret->data);
	else
	{
		printf("\n");
	}
	DestroyList(&head);
}

void test9()
{
	pNode p1 = NULL;
	pNode p2 = NULL;
	pNode newhead = NULL;
	InitLinkList(&p1);
	InitLinkList(&p2);
	PushBack(&p1, 1);
	PushBack(&p1, 3);
	PushBack(&p1, 5);
	PushBack(&p1, 7);
	Display(p1);
	PushBack(&p2, 0);
	PushBack(&p2, 2);
	PushBack(&p2, 4);
	PushBack(&p2, 6);
	PushBack(&p2, 8);
	Display(p2);
	newhead=Merge(p1,p2);
	Display(newhead);
	/*DestroyList(&newhead);*/

}

void test10()
{
	pNode p1 = NULL;
	PushBack(&p1, 1);
	PushBack(&p1, 3);
	PushBack(&p1, 5);
	PushBack(&p1, 7);
	Display(p1);
	DelKNode(p1, 12);
	Display(p1);
	DestroyList(&p1);
}

void test11()
{
	pNode ret = NULL;
	pNode p1 = NULL;
	PushBack(&p1, 1);
	PushBack(&p1, 3);
	PushBack(&p1, 5);
	PushBack(&p1, 7);
	PushBack(&p1, 8);
	PushBack(&p1, 9);
	PushBack(&p1, 10);
	Find(p1, 10)->next = Find(p1, 7);
	ret = CheckCycle(p1);
	if (ret == NULL)
	{
		printf("no\n");
	}
	else
		printf("yes\n");

}

void test12()
{
	pNode pos = NULL;
	pNode p1 = NULL;
	PushBack(&p1, 1);
	PushBack(&p1, 3);
	PushBack(&p1, 5);
	PushBack(&p1, 7);
	PushBack(&p1, 8);
	PushBack(&p1, 9);
	PushBack(&p1, 10);
	Find(p1, 10)->next = Find(p1, 7);
	pos = CheckCycle(p1);
	int tmp = GetCircleLength(pos);
	printf("%d\n", tmp);

}
void test13()
{
	pNode pos = NULL;
	pNode p1 = NULL;
	pNode ret = NULL;
	PushBack(&p1, 1);
	PushBack(&p1, 3);
	PushBack(&p1, 5);
	PushBack(&p1, 7);
	PushBack(&p1, 8);
	PushBack(&p1, 9);
	PushBack(&p1, 10);
	Find(p1, 10)->next = Find(p1, 3);
	pos = CheckCycle(p1);
	if (pos == NULL)
	{
		printf("no\n");
	}
	else
	{
		ret=GetCircleEntryNode(pos, p1);
		printf("%d\n", ret->data);
	}
}

void test14()
{
	pNode meet = NULL;
	pNode p1 = NULL;
	pNode p2 = NULL;
	PushBack(&p1, 1);
	PushBack(&p1, 3);
	PushBack(&p1, 5);
	PushBack(&p1, 7);
	PushBack(&p1, 8);
	PushBack(&p1, 9);
	PushBack(&p1, 10);

	PushBack(&p2, 2);
	PushBack(&p2, 4);
	PushBack(&p2, 6);
	Find(p2, 6)->next = Find(p1, 7);
	meet=CheckCross(p1, p2);
	if (meet == NULL)
	{
		printf("不相交");
	}
	else
	{
		printf("相交\n");
		printf("%d\n", meet->data);
	}
	Display(p1);
	Display(p2);

}

void test15()
{
	pNode p2 = NULL;
	pNode p1 = NULL;
	for (int i =1; i<=41; i++)
	{
		PushBack(&p1, i);
	}
	Find(p1, 41)->next = Find(p1, 1);
	p2 = Find(p1, 1);
	JosephCycle(p2, 3);
}

int main()
{
	//test1();    //尾插、尾删
	//test2();    //头插、头删
	//test3();    //指定位置插入数据
	//test4();    //逆序
	//test5();    //测试逆序打印函数
	//test6();    //删除无头非为节点
	//test7();    //排序
	//test8();    //找中间节点
	//test9();    //两条有序链的合并,合并之后依然有序
	//test10();   //删除倒数第k个节点
	//test11();   //判断是否带环
	//test12();   //求环的长度
	//test13();   //求环的进入点
	//test14();   //判断两条链是否相交
	test15();   //约瑟夫环

	system("pause");
	return 0;
}

各种功能都实现了,但是有的比较麻烦,有简单方法的大神们可以留言。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值