【面试官让我十分钟实现一个链表?一个双向带头循环链表甩给面试官】

news2024/12/26 17:33:51

我们在面试中面试官一般都会让我们现场写代码,如果你面试的时候面试官让你十分钟写一个链表,你是不是懵逼了?十分钟写一个链表,怎么可能?事实上是有可能的,十分钟写出的链表也能震惊面试官。

我们学习单链表其实是为了后面学习更高级的数据结构,因为单链表一般不会用来存储数据,只是用来作为更高级数据结构的子结构,如哈希桶、图的邻接表等。单链表看似简单,其实一点也不简单,在进行增删改查操作的时候需要注意很多问题。

在实际中,我们一般使用双向带头循环链表存储数据,因为在链表结构中,双向带头循环链表可以说是链表当中最优的结构了。双向带头循环链表,名字听起来很高大上,看起来很难的样子,其实不是的,它就是一个纸老虎,看起来难,其实它的实现很容易。

 双向带头循环链表有一个数据域和两个指针域,第一个指针域指向直接后继,第二个指针域指向直接前驱。表中最后一个节点的第二个指针域指向头节点,头节点的第一个指针域指向最后一个节点,整个链表形成一个环。

双向带头循环链表的结构

typedef int DListDataType;
typedef struct DListNode
{
	DListDataType* data;
	struct DListNode* prev;
	struct DListNode* next;
}DListNode;

链表节点的创建

DListNode* BuyListNode(DListDataType x)
{
	DListNode* node = (DListNode*)malloc(sizeof(DListNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	node->data = x;
	node->prev = NULL;
	node->next = NULL;
	return node;
}

链表的初始化

 创建一个头节点,让头节点的两个指针域都分别指向自己。

DListNode* LTInit()
{
	DListNode* phead = BuyListNode(-1);//头节点的data可以为任意值
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

链表的打印

void LTPrint(DListNode* phead)
{
	assert(phead);

	DListNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

 链表的尾插

 

void LTPushBack(DListNode* phead, DListDataType x)
{
	assert(phead);
	DListNode* newnode = BuyListNode(x);
	DListNode* tail = phead->prev;//保存尾节点(头节点的prev)

	tail->next = newnode;
	newnode->prev = tail;

	newnode->prev = phead;
	phead->prev = newnode;
	
}

 链表的尾删

void LTPopBack(DListNode* phead)
{
	assert(phead);
	assert(phead->next != phead);  // 判断是否为空

	DListNode* tail = phead->prev;

	tail->prev->next = phead;
	phead->prev = tail;
	free(tail);
}

 链表的头插

void LTPushFront(DListNode* phead, DListDataType x)
{
	assert(phead);
	DListNode* newnode = BuyListNode(x);
	newnode->next = phead->next;
	phead->next->prev = newnode;

	phead->next = newnode;
	newnode->prev = phead;
	
}

链表的头删

void LTPopFront(DListNode* phead)
{
	assert(phead);
	assert(phead->next != phead);  // 判断是否为空

	DListNode* pheadnext = phead->next;

	phead->next = pheadnext->next;
	pheadnext->next->prev = phead;
	free(pheadnext);
}

在链表中插入节点

 

// pos位置之前插入
void LTInsert(DListNode* pos, DListDataType x)
{
	assert(pos);
	DListNode* prevpos = pos->prev;
	DListNode* newnode = BuyListNode(x);
	// prev newnode pos
	prevpos->next = newnode;
	newnode->prev = prevpos;
	newnode->next = pos;
	pos->prev = newnode;
}

删除链表中的节点

// 删除pos位置
void LTErase(DListNode* pos)
{
	assert(pos);
	DListNode* prevpos = pos->prev;
	DListNode* nextpos = pos->next;

	free(pos);
	prevpos->next = nextpos;
	nextpos->prev = prevpos;

}

 判断链表是否为空

bool LTEmpty(DListNode* phead)
{
	assert(phead);

	/*if (phead->next == phead)
	{
		return true;
	}
	else
	{
		return false;
	}*/

	return phead->next == phead;
}

计算链表的节点

size_t LTSize(DListNode* phead)
{
	assert(phead);

	size_t size = 0;
	DListNode* cur = phead->next;
	while (cur != phead)
	{
		++size;
		cur = cur->next;
	}

	return size;
}

 销毁链表

void LTDestroy(DListNode* phead)
{
	assert(phead);

	DListNode* cur = phead->next;
	while (cur != phead)
	{
		DListNode* next = cur->next;
		free(cur);

		cur = next;
	}
	free(phead);
}

以上就是带头双向链表的基本操作,如果想在十分钟之内写出这个链表,只需要在头插,尾插复用

 LTInsert(),头删,尾删复用 LTErase(),这样你只需要写出LTInsert()和 LTErase()就等于将头插,尾插、头删,尾删写出来了。

完整代码:

DList.h  接口函数

#include <assert.h>
#include <stdbool.h>

typedef int DListDataType;
typedef struct DListNode
{
	DListDataType* data;
	struct DListNode* prev;
	struct DListNode* next;
}DListNode;

DListNode* BuyListNode(DListDataType x);
void LTPrint(DListNode* phead);
DListNode* LTInit();
void LTPushBack(DListNode* phead, DListDataType x);
void LTPopBack(DListNode* phead);

void LTPushFront(DListNode* phead, DListDataType x);
void LTPopFront(DListNode* phead);
DListNode* LTFind(DListNode* phead, DListDataType x);

// pos位置之前插入
void LTInsert(DListNode* pos, DListDataType x);
// pos位置之后插入
void LTErase(DListNode* pos);

bool LTEmpty(DListNode* phead);
size_t LTSize(DListNode* phead);
void LTDestroy(DListNode* phead);

DList.c  函数的实现

#include "DList.h"

DListNode* BuyListNode(DListDataType x)
{
	DListNode* node = (DListNode*)malloc(sizeof(DListNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	node->data = x;
	node->prev = NULL;
	node->next = NULL;
	return node;
}
DListNode* LTInit()
{
	DListNode* phead = BuyListNode(-1);//头节点的data可以为任意值
	phead->next = phead;
	phead->prev = phead;
	return phead;
}
void LTPrint(DListNode* phead)
{
	assert(phead);

	DListNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
void LTPushBack(DListNode* phead, DListDataType x)
{
	assert(phead);
	//DListNode* newnode = BuyListNode(x);
	//DListNode* tail = phead->prev;//保存尾节点(头节点的prev)

	//tail->next = newnode;
	//newnode->prev = tail;

	//newnode->prev = phead;
	//phead->prev = newnode;

	LTInsert(phead, x);
	
}
void LTPopBack(DListNode* phead)
{
	assert(phead);
	//assert(phead->next != phead);  // 判断是否为空

	//DListNode* tail = phead->prev;

	//tail->prev->next = phead;
	//phead->prev = tail;
	//free(tail);

	LTErase(phead->prev);
}

void LTPushFront(DListNode* phead, DListDataType x)
{
	assert(phead);
	/*DListNode* newnode = BuyListNode(x);
	newnode->next = phead->next;
	phead->next->prev = newnode;

	phead->next = newnode;
	newnode->prev = phead;*/
	
	LTInsert(phead->next, x);

}
void LTPopFront(DListNode* phead)
{
	assert(phead);
	//assert(phead->next != phead);  // 判断是否为空

	//DListNode* pheadnext = phead->next;

	//phead->next = pheadnext->next;
	//pheadnext->next->prev = phead;
	//free(pheadnext);
	LTErase(phead->next);
}
DListNode* LTFind(DListNode* phead, DListDataType x)
{
	assert(phead);
	DListNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

// pos位置之前插入
void LTInsert(DListNode* pos, DListDataType x)
{
	assert(pos);
	DListNode* prevpos = pos->prev;
	DListNode* newnode = BuyListNode(x);
	// prev newnode pos
	prevpos->next = newnode;
	newnode->prev = prevpos;
	newnode->next = pos;
	pos->prev = newnode;
}
// 删除pos位置
void LTErase(DListNode* pos)
{
	assert(pos);
	DListNode* prevpos = pos->prev;
	DListNode* nextpos = pos->next;

	free(pos);
	prevpos->next = nextpos;
	nextpos->prev = prevpos;

}

bool LTEmpty(DListNode* phead)
{
	assert(phead);

	/*if (phead->next == phead)
	{
		return true;
	}
	else
	{
		return false;
	}*/

	return phead->next == phead;
}
size_t LTSize(DListNode* phead)
{
	assert(phead);

	size_t size = 0;
	DListNode* cur = phead->next;
	while (cur != phead)
	{
		++size;
		cur = cur->next;
	}

	return size;
}
void LTDestroy(DListNode* phead)
{
	assert(phead);

	DListNode* cur = phead->next;
	while (cur != phead)
	{
		DListNode* next = cur->next;
		free(cur);

		cur = next;
	}
	free(phead);
}

Test.c   测试函数

#include "DList.h"

void TestList1()
{
	DListNode* phead = LTInit();
	LTPushBack(phead, 1);
	LTPushBack(phead, 2);
	LTPushBack(phead, 3);
	LTPushBack(phead, 4);
	LTPushBack(phead, 5);
	LTPrint(phead);

	LTPopBack(phead);
	LTPrint(phead);
	LTPopBack(phead);
	LTPrint(phead);
	LTPopBack(phead);
	LTPrint(phead);
	LTPopBack(phead);
	LTPrint(phead);
	LTPopBack(phead);
	LTPrint(phead);

	//LTPopBack(phead);
}

void TestList2()
{
	DListNode* phead = LTInit();
	LTPushFront(phead, 1);
	LTPushFront(phead, 2);
	LTPushFront(phead, 3);
	LTPushFront(phead, 4);
	LTPushFront(phead, 5);
	LTPrint(phead);

	LTPopFront(phead);
	LTPrint(phead);
	LTPopFront(phead);
	LTPrint(phead);
	LTPopFront(phead);
	LTPrint(phead);
	LTPopFront(phead);
	LTPrint(phead);
	LTPopFront(phead);
	LTPrint(phead);
}

void TestList3()
{
	DListNode* phead = LTInit();
	LTPushFront(phead, 1);
	LTPushFront(phead, 2);
	LTPushFront(phead, 3);
	LTPushFront(phead, 4);
	LTPushFront(phead, 5);
	LTPrint(phead);

	DListNode* pos = LTFind(phead, 3);
	LTPrint(phead);

	LTDestroy(phead);
	phead = NULL;
}

int main()
{
	
	TestList1();
	//TestList2();
	//TestList3();
	return 0;
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/4933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《红楼梦》诗词大全

前言&#xff1a; 博主最近二读红楼&#xff0c;幼时只觉此书开篇便人物繁杂、莺莺燕燕似多混乱&#xff0c;开篇只看黛玉哭闹了几次&#xff0c;便弃书不读&#xff0c;只觉困惑&#xff0c;其何敢称六大奇书或四大名著&#xff1f; 今日书荒&#xff0c;偶然间再次拾起红楼…

3.2 网络协议

0 socket协议 访问 Internet 使用得最广泛的方法&#xff1b;所谓socket通常也称作"套接字"&#xff0c;用于描述IP地址和端口&#xff0c;是一个通信链的句柄&#xff1b;应用程序通常通过"套接字"向网络发出请求或者应答网络请求&#xff1b;Socket接口…

六六大顺 马蹄集

六六大顺 难度&#xff1a;白银 0时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 输入正整数N,输出N以内&#xff08;含N),6的倍数&#xff0c;并且包含6的数字&#xff0c;比如36等。 格式 输入格式&#xff1a;输入整型 输出格式&#xff1a;输出整型&#xff0c;空格分…

SI24R1国产低功耗2.4GHz收发一体射频遥控工控答题卡方案芯片替代NRF24L01+

目录SI24R1简介芯片特性硬件设计参考2.4GHz射频芯片选型参考应用领域SI24R1简介 Si24R1 2.4GHz收发一体芯片量产于2012年&#xff0c;由于其一致性稳定性高、低功耗、远距离、兼容替代NRF24L01&#xff0c;兼容NORDIC 2.4GHz协议等特点&#xff0c;一直广泛应用于各物联网场景…

牛客竞赛每日俩题 - 动态规划2

目录 经典DP - 走方格 走方格2.0 分割回文串 分割回文串 - 回文优化 经典DP - 走方格 不同路径的数目(一)_牛客题霸_牛客网 状态&#xff1a; 子状态&#xff1a;从(0,0)到达(1,0),(1,1),(2,1),...(m-1,n-1)的路径数 F(i,j): 从(0,0)到达F(i,j)的路径数 状态递推&#xff1a…

【23届秋招总结系列】一个普本23届小学弟的秋招总结,上岸金山云开发(云计算方向)

大家好&#xff0c;我是路飞~ 正值秋招收尾阶段&#xff0c;今天很荣幸请来了交流qun小分队里的一位23届本科上岸 金山云开发工程师-云计算方向的同学&#xff0c;给大家分享一下他在秋招过程中的总结和心得体会。 他的博客链接&#xff1a;团子的守护 一、秋招收获 2022.1…

计算机毕业设计SSM大学生创新创业项目活动管理平台【附源码数据库】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【微服务】Nacos服务发现源码分析

&#x1f496;Spring家族及微服务系列文章 ✨【微服务】SpringBoot监听器机制以及在Nacos中的应用 ✨【微服务】Nacos服务端完成微服务注册以及健康检查流程 ✨【微服务】Nacos客户端微服务注册原理流程 ✨【微服务】SpringCloud中使用Ribbon实现负载均衡的原理 ✨【微服务】Sp…

Ubuntu20.04安装k8s v1.21.0

1. 禁用swap分区, 修改网络配置 sudo vim /etc/fstab 把有swap的那一行注释掉即可&#xff0c;如下&#xff1a; 然后执行如下命令 cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 EOF …

12.帖子模块——使用peewee创建多表关联的结构,使用Tornado创建查询接口、增加接口

1.模型建立与数据初始化 1.1分析建立表所需要的字段 本次主要是添加一个帖子展示时&#xff0c;所需要的内容&#xff0c;这里就得创建一个mysql的数据表去存储它的内容。 1.2 使用peewee创建多表关联结构Model 模型建立 # forum/models.py # 用于创建数据表模型from peewe…

企业自研业务系统的登录如何添加动态口令,实施MFA双因子认证?

一、背景需求 不少企业因业务需要会自己研发业务系统&#xff0c;为保护业务数据安全&#xff0c;首先要确保能访问到业务数据的人员“身份”安全可信。 企业自研业务系统的账号密码基本是 IT 管理员单独管理维护&#xff0c;员工为了方便记忆&#xff0c;通常设置与其他商采系…

函数绘图仪 MathGrafix 12.1 Crack

函数绘图仪 MathGrafix 12.1 MatheGrafix 12.1于 2022 年 8 月 1 日发布&#xff0c;包含两个新模块&#xff1a; 公式函数模块支持具有一个变量和最多十个参数的函数方程。每个参数都可以使用自动运行的滑块进行调整。 在数据模块中&#xff0c;记录数据后&#xff0c;使用回…

网页制作基础大二dw作业HTML+CSS+JavaScript云南我的家乡旅游景点

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

【C++笔试强训】第二十一天

&#x1f387;C笔试强训 博客主页&#xff1a;一起去看日落吗分享博主的C刷题日常&#xff0c;大家一起学习博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a;夜色难免微凉&#xff0c;前方必有曙光 &#x1f31e;。 &#x1f4a6;&a…

装饰模式与职责链模式笔记

装饰模式&#xff08;Decorator&#xff09; 概念 动态地给一个对象添加一些额外的职责&#xff0c;就增加功能来说&#xff0c;装饰模式比生成子类更为灵活。UML类图&#xff1a; 代码 给人打扮 //人类(ConcreteComponent) public class Person {private String name;public…

[附源码]java毕业设计ssm实验教学资源管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

C语言笔记第03章:数组

了解更多关注中南林业科技大学软件协会官网&#xff1a;https://www.csuftsap.cn/ 来自软件协会编辑&#xff0c;注册会员即可获取全部开源.md资源&#xff0c;请勿转载&#xff0c;归软件协会所有。 任何问题联系软件协会。 文章目录:star: 数组1.八个老婆引出数组 - 为什么…

1.7.2、计算机网络体系结构分层的必要性

1.7.2、计算机网络体系结构分层的必要性 计算机网络是个非常复杂的系统\color{red}计算机网络是个非常复杂的系统计算机网络是个非常复杂的系统。早在最初的ARPANET设计时就提出了分层的设计理念。 "分层\color{red}分层分层"可将庞大而复杂的问题&#xff0c;转化为…

一专多能、创新力十足,南大通用GBase8c数据库获鲲鹏创新应用大赛金奖

被评为openGauss赛道金奖的多模多态分布式数据库GBase 8c其含金量表现在哪些方面&#xff1f;基于openGauss有哪些技术创新&#xff1f; 其商业价值是什么&#xff1f;在哪些场景发挥作用&#xff1f; 面向全球开发者的年度顶级赛事——鲲鹏应用创新大赛已经举办三个年头了。三…

DHCP协议从入门到部署DHCP服务器进行实验

目录 1、DHCP基本概念 2、DHCP的优点 3、DHCP的工作原理 4、通过抓包验证原理 5、在windows server上部署DHCP服务器 6、实验搭建 实验环境 配置R1的中继 常见报文学习 1、DHCP基本概念 路由器可以阻挡DHCP discover的广播报文 2、DHCP的优点 3、DHCP的工作原理 4、通过抓…