【数据结构(二)】线性表(三)链式存储结构之单链表

链式存储结构

单链表的定义
  • 数据域:存储数据元素信息的域称为数据域。

  • 指针域:存储直接后继位置的域称为指针域。

  • 链:指针域中存储的信息称为指针或链。

  • 结点:数据域和指针域的信息组成数据元素ai的存储映像,即为结点。

  • 链式存储结构:n个结点链结成一个链表,即为线性表的链式存储结构。

  • 单链表:链表中每个结点只包含一个指针域的链表称为单链表。

  • 头指针:链表中第一个结点的存储位置叫做头指针。

  • 链表中最后一个结点指针为“空”(NULL或“^”)。

  • 头结点:链表第一个结点前附设的一个结点,且数据域可以不存储任何信息。(方便操作统一,也可没有)

  • 单链表的存储结构:

typedef struct Node
{
	ElemType data;
	struct Node *next;
}Node;
typedef struct Node *LinkList;		//定义LinkList
单链表的读取
  • GetElem
Int GetElem(LinkList L,int i,ElemType *e)
{
	LinkList p;		//声明一个指针
	p=L->next;		//让p指向链表的第一个结点
	int j=1;
	while(p && j<i)		//p不为空且计数器未等于i时
	{
		p=p->next;		//重复使p指向下一个结点,直到p为空或找到第i个结点
		++j;
	}
	if(!p || j>i)		//若p为空或计数器大于i
		return 0;		//第i个结点不存在
	*e=p->date;		//获取第i个结点的数据
	return 1;
}
  • 时间复杂度为O(n)。
单链表的插入与删除
  • 插入ListInsert:只需改变插入结点的指针域和插入位置前的结点的指针域即可。
Int ListInsert(LinkList *L,int i,ElemType e)
{
	LinkList p;		//定义插入位置的前一个的结点
	LinkList s;		//定义需要插入的结点
	p = *L;
	int j = 1;
	while(p && j < i)	//寻找第i-1个结点
	{
		p = p->next;
		++j;
	}
	if(!p || j>i)		//若p为空或计数器大于i
		return 0;		//第i个结点不存在
	s = (LinkList)malloc(sizeof(Node));		//生成新结点
	s->data = e;
	s->next = p->next;		//将p的后继结点赋值给s的后继
	p->next = s;		//将s赋值给p的后继
	return 1;
  • 删除ListDelete:原理同插入。
Int ListDelete(LinkList *L,int i,ElemType e)
{
	LinkList p;		//定义删除位置的前一个的结点
	LinkList q;		//定义需要删除的结点
	p = *L;
	int j = 1;
	while(p && j < i)	//寻找第i-1个结点
	{
		p = p->next;
		++j;
	}
	if(!p || j>i)		//若p为空或计数器大于i
		return 0;		//第i个结点不存在
	q = p->next;		//定位q
	p->next = q->next;		//将q的后继赋值给p的后继
	*e = q->data;		//将q的数据赋值给e
	free(q);		//删除此结点,释放内存
	return 1;
}
  • 时间复杂度为O(n),但在同一位置插入大量结点时,确定位置的时间复杂度为O(n),不断的插入和删除都为O(1)。
  • 结论:对于插入或者删除数据越频繁的操作,单链表的效率优势越明显。
单链表的整表创建和删除
  • 头插法创建
void CreateListHead(LinkList *L, int n)
{
	LinkList p;
	srand (time (0));		//初始化随机数种子
	*L= (LinkList) malloc (sizeof (Node));
	(*L)->next = NULL;  		//建立一个带头节点的单链表
	for(int i = 0; i < n; i++)
	{
		p = (LinkList) malloc (sizeof (Node));		//生成新结点
		p->date = rand () %100 + 1;		//随机生成100以内的数字
		p->next = (*L)->next;
		(*L)->next = p;		//插入到表头
	}
}
  • 尾插法创建
void CreateListHead(LinkList *L, int n)
{
	LinkList p, r;
	srand (time (0));		//初始化随机数种子
	*L= (LinkList) malloc (sizeof (Node));		//建立整个线性表
	r = *L;		//r指向尾部的结点
	for(int i = 0; i < n; i++)
	{
		p = (Node *) malloc (sizeof (Node));		//生成新结点
		p->date = rand () %100 + 1;		//随机生成100以内的数字
		r->next = p;		//将末端结点指向新结点
		r = p;		//将新节点定义为末端结点
	}
	r->next = NULL;		//末端结点无指针域,当前链表结束
}
  • 整表删除
Int ClearList(LinkList *L)
{
	LinkList p,q;
	p=(*L)->next;		//p指向第一个结点
	while(p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;		//头节点指针域为空
	return 1;
}
单链表结构&顺序存储结构
  • 若线性表需频繁查找,很少进行插入删除时,选用顺序存储结构。如游戏开发中的用户个人信息。
  • 若线性表需要频繁的插入和删除时,选用单链表结构。如游戏玩家的背包列表。
  • 若事先知道线性表的大致长度,则选用顺序存储结构。
  • 若线性表中元素个数变化较大,则选用单链表结构。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值