第3章 线性表 链式存储结构知识点及代码实现【带注释】

3.6链式存储结构

解决顺序存储结构在插入与删除时需要移动大量元素。

定义:

为了表示每个数据元素与其直接后继元素之间的关系,除了存储其本身的信息外,还需存储一个指示其直接后继的信息。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。
这两部分信组成数据元素的存储映像,称为结点。
单链表

另外,会在单链表的第一个结点之前附设一个结点,称为头结点。头结点不存储信息,可以存储如线性表的长度等附加信息,指针域存储指向第一个结点的指针。

头指针与头结点的异同

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

初读至此,开始心生疑惑,这里的头指针怎么一会说指向的是第一个结点,一会儿又是指向头结点嘞?
参考下文中图3-6-6以及图3-6-7,我发现原来自己的把头指针与头结点的概念混淆了,认为头指针即为头结点的指针域。
在这里插入图片描述

3.7 单链表的读取

算法思路
  1. 声明一个指针p指向链表的第一个结点,初始化j从1开始。
  2. 当j<i时,将指针向后移动,不断指向下一结点,并对j进行累加。
  3. 若链表末尾p为空时,则说明第i个结点不存在。
  4. 否则,返回结点p的数据。
注意

由于这里并不能确定循环次数,所以无法使用for循环,主要核心思想“工作指针后移”。

3.8 单链表的插入与删除

插入算法思路
  1. 声明一个指针p指向链表的第一个结点,初始化j从1开始。
  2. 当j<i时,将指针向后移动,不断指向下一结点,并对j进行累加。
  3. 若链表末尾p为空时,则说明第i个结点不存在。
  4. 否则查找成功,在系统中生成一个空结点s。
  5. 将数据元素赋值给s->data;
  6. 单链表的插入标准语句s->next=p->next;p->next=s;
  7. 返回成功。
    注:【这里的步骤中的1-3与单链表的读取相同,就是通过不断后移指针,找到对应i位置】
删除算法思路
  1. 声明一个指针p指向链表的第一个结点,初始化j从1开始。
  2. 当j<i时,将指针向后移动,不断指向下一结点,并对j进行累加。
  3. 若链表末尾p为空时,则说明第i个结点不存在。
  4. 否则查找成功,将欲删除的结点p->next赋值给q;
  5. 单链表的删除标准语句p->next=q->next;
  6. 将q结点中的数据赋值给e,作为返回;
  7. 释放q结点
  8. 返回成功

静态链表、循环链表、双向链表

  1. 用数组表示的链表叫做静态链表
  2. 将单链表中终端结点由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表
  3. 双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针。
单链表代码实现
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define OK 1
#define ERROR 0

typedef int ElemType;
typedef int status;
//结点由数据域和指针域,指针域存放下一结点的地址
typedef struct Node 
{
	ElemType data;
	struct Node *next;
}Node;
typedef struct Node *LinkList;

status InitList(LinkList *L)
{
	*L = (LinkList)malloc(sizeof(Node));
	if (!(*L))
		return ERROR;//存储分配失败
	(*L)->next = NULL;//指针域为空

	return OK;
}

/*初始条件:顺序线性表L已存在,并且i的位置也符合要求
操作结果:用e返回L中第i个数据元素的值*/
status GetElement(LinkList L, int i, ElemType *e)
{
	LinkList p;
	int j;
	p = L->next;
	j = 1;
	while (p&&j < i)
	{
		p = p->next;
		++j;
	}
	if (!p || j > i)
	{
		return ERROR;
	}
	*e = p->data;
}

//插入
status ListInsert(LinkList *L, int i, ElemType e)
{
	LinkList p, s;
	int j;
	p = (*L)->next;
	j = 1;
	while (p&&j < i)
	{
		p = p->next;
		++j;
	}
	if (!p || j > i)
		return ERROR;
	//进行到这里即线性表中存在第i个位置可以用来插入
	s = (LinkList)malloc(sizeof(Node));
	s->data = e;
	//
	s->next = p->next;
	p->next = s;

	return OK;
}

//删除,并返回对应位置的元素
status ListDelete(LinkList *L, int i, ElemType *e)
{
	LinkList p, q;
	int j;
	p->next = (*L);
	j = 1;
	while (p&&j < i)
	{
		p = p->next;
	}
	if (!p || j > i)
		return ERROR;
	//找到对应位置
	q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);//让系统回收此结点,释放内存

	return OK;
}

/*单链表的整表创建*/
/*头插法:插入位置在头结点与next位置之间,其方法与普通插入相同*/
void CreateListHead(LinkList *L, int n)
{
	LinkList p;
	int i;
	srand(time(0));
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL;
	for (i = 0; i < n; i++)
	{
		p = (LinkList)malloc(sizeof(Node));
		p->data = rand() % 100 + 1;//随机生成100以内的的数字
		p->next = (*L)->next;
		(*L)->next = p;
	}

}

/*尾插法*/
void CreateListTail(LinkList *L, int n)
{
	LinkList p, r;//这里的r指向尾结点
	int i;
	srand(time(0));
	*L = (LinkList)malloc(sizeof(Node));//生成头结点
	r = *L;
	for (i = 0; i < n; i++)
	{
		p = (LinkList)malloc(sizeof(Node));
		p->data = rand() % 100 + 1;//生成随机数
		r->next = p;
		r = p;//将r的后继结点设为p,然后将当前的新结点定义为表尾终端结点
	}
}

status ClearList(LinkList *L)
{
	LinkList p, q;
	p = (*L)->next;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return OK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火柴先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值