数据结构与算法学习笔记02_2(线性表)

数据结构与算法学习笔记02_2(线性表)

 

2、线性表的链式存储结构

 

单链表

除了存储其本身的信息外,还需存储一个指示其直接后继的存储位置的信息。

我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。链表中的第一个结点的存储位置叫做头指针,最后一个结点指针为(NULL)

 

头指针与头结点的异同

1、头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。

2、头指针是链表的必要元素

3、头结点是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(但也可以用来存放链表的长度)。

4、头结点不一定是链表的必须要素

 


实现:

typedefstructNode

{

       ElemType  data;     // 数据域

       struct  Node*Next// 指针域

} Node;

typedef  struct Node*LinkList;

 

单链表的读取:

获得链表第i个数据的算法思路:

声明一个结点p指向链表第一个结点,初始化j从1开始;

当j<i时,就遍历链表,让p的指针向后移动,不断指向一下结点,j+1;

若到链表末尾p为空,则说明第i个元素不存在;

否则查找成功,返回结点p的数据。

实现:

status GetElem(LinkList L, int i, ElemType* e){
	int j;
	LinkList p;
	p = L->next;
	j = 1;
	
	while (p&&j<i)
	{
		p = p->next;
		++j;
	}
	if (!p||j>i)
	{
		return ERROR;
	}
	*e = p->data;
	return Ok;
}

由于单链表的结构中没有定义表长,所以不能实现知道要循环多少次,因此也就不方便使用for来控制循环。

 

单链表的插入


我们思考后发觉根本用不着惊动其他结点,只需要让s->next和p->next的指针做一点改变。

s->next= p->next;

p->next= s;

这两句是无论如何不能弄反的。

 

单链表第i个数据插入结点的算法思路:

声明一结点p指向链表头结点,初始化j从1开始;

当j<1时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1;

若到链表末尾p为空,则说明第i个元素不存在;

否则查找成功,在系统中生成一个空结点s;

将数据元素e赋值给s->data;

单链表的插入刚才两个标准语句;

返回成功。

实现:

Status ListInsert(LinkList* L, int i, ElemType e){
	int j;	
	LinkList p, s;

	p = *L;
	j = 1;

	while (p&&j<i)
	{
		p = p->next;
		j++
	}
	if (!p||j>i)
	{
		return ERROR;
	}
	s = (Listlist)malloc(sizeof(Node));
	s->data = e;

	s->next = p->next;
	p->next = s;
	return Ok;
}

单链表的删除


单链表第i个数据删除结点的算法思路:

声明结点p指向链表第一个结点,初始化j=1;

当j<1时,就遍历链表,让P的指针向后移动,不断指向下一个结点,j累加1;

若到链表末尾p为空,则说明第i个元素不存在;

否则查找成功,将欲删除结点p->next赋值给q;

单链表的删除标准语句p->next = q->next;

将q结点中的数据赋值给e,作为返回;

释放q结点。

实现:

Status ListDelete(LinkList *L, int i, ElemType *e){
	int j;
	LinkList p, q;

	p = *L;
	j = 1;
	
	while (p->next&&j<i)
	{
		p = p->next;
		++j;
	}
	if (!(p->next)||j>i)
	{
		return ERROR;
	}
	q = p->next;
	p->next = q->next;

	*e = q->data;
	free(q);

	return Ok;
}

效率分析:

无论是单链表插入还是删除算法,它们其实都是由两个部分组成:第一部分就是遍历查找第i个元素,第二部分就是实现插入和删除元素。从整个算法来说,我们很容易可以推出它们的时间复杂度都是O(n)。

 

再详细点分析:

如果在我们不知道第i个元素的指针位置,单链表数据结构在插入和删除操作上,与线性表的顺序存储结构是没有太大优势的。

但如果,我们希望从第i个位置开始,插入连续10个元素,对于顺序存储结构意味着,每一次插入都需要移动n-i个位置,所以每次都是O(n)。

 

而单链表,我们只需要在第一次时,找到第i个位置的指针,此时为O(n),接下来只是简单地通过赋值移动指针而已,时间复杂度都是O(1)。

显然,对于插入或删除数据越频繁的操作,单链表的效率优势就越是明显啦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值