数据结构—线性表2

目录

线性表的链式表示和实现

1、链表概念

1.1与链式存储有关的术语

1.2讨论

2、单链表

2.1单链表的定义和表示

2.2单链表基本操作的实现


线性表的链式表示和实现

1、链表概念

链式存储结构:结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻

线性表的链式表示又称为非顺序映像链式映像

各结点由两个域组成:

  • 数据域:存储元素数值数据
  • 指针域:存储直接后继结点的存储位置

1.1与链式存储有关的术语

1、结点:数据元素的存储映像

2、链表:n个结点由指针链组成一个链表,它是线性表的链式存储映像,称为线性表的链式存储结构

 3、单链表、双链表、循环链表:

  • 结点只有一个指针域的链表,称为单链表或线性链表
  • 结点有两个指针域的链表,称为双链表
  • 首尾相接的链表称为循环链表

 4、头指针、头结点和首元结点:

  • 头指针:是指向链表中第一个结点的指针
  • 首元结点:是指链表中存储第一个数据元素的结点
  • 头结点:是在链表的首元结点之前附设的一个结点

1.2讨论

讨论1:如何表示空表?

  • 无头结点时,头指针为空时表示空表
  • 有头结点时,当头结点的指针域为空时表示空表

讨论2:在链表中设置头结点有什么好处?

1、便于首元结点的处理

        首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置的操作和其他位置一致,无需进行特殊处理;

2、便于空表和非空表统一处理

        无论链表是否为空,头指针都是指向头结点的非空指针,因此空空表和非空表的处理也就统一了。

 讨论3:头结点的数据域内装的是什么?

        头结点的数据域可以为空,可以放置表长度,但此结点不能计入链表长度值。

2、单链表

2.1单链表的定义和表示

带头结点的单链表

单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名,若头指针名是L,则把链表称为表L。

2.2单链表基本操作的实现

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int ElemType;
typedef int Status;

typedef struct Lnode {
	int data;
	struct Lnode* next;
}Lnode, * LinkList;

单链表的初始化(带头结点的单链表)

  1. 生成新结点作头结点,用头指针L指向头结点。
  2. 将头结点的指针域置空
Status InitList_L(LinkList* L) {
	(*L) = (LinkList)malloc(sizeof(Lnode));
	if (!(*L)) /* 存储分配失败 */
		return ERROR;
	(*L)->next = NULL;
	return OK;
}

判断链表是否为空

  • 判断头结点指针域是否为空
Status ListEmpty(LinkList L) {
	if (L->next)
		return FALSE;
	else
		return TRUE;
}

单链表的销毁

  • 从头指针开始,依次释放所有结点
Status Destory_L(LinkList* L) {
	Lnode* p;
	while (L) {
		p = *L;
		*L = (*L)->next;
		free(p);
	}
	return OK;
}

清空链表

  • 依次释放所有结点,并将头结点指针域设置为空
Status ClearList(LinkList* L) {
	Lnode* p, * q;
	p = (*L)->next;
	while (p) {
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return OK;
}

求单链表的表长

  • 从首元结点开始,依次计数所有结点
int LengthList_L(LinkList L) {
	Lnode* p;
	p = L->next;
	int i = 0;
	while (p) {
		i++;
		p = p->next;
	}
	return i;
}

取值——取单链表中第i个元素的内容

  • 从链表的头指针出发,顺着链域next逐个结点往下搜索,直至搜索到第i个结点为止。
Status GetElem_L(LinkList L, int i, ElemType* e) {
	int j = 1;
	LinkList p = L->next;
	while (p && j < i) {
		p = p->next;
		++j;
	}
	if (!p || j > i)
		return ERROR;
	*e = p->data;
	return OK;
}

按值查找

  • 根据指定数据获取改数据所在的位置(地址)
Lnode* LocateElem_L(LinkList L, ElemType e) {
	LinkList p = L->next;
	while (p && p->data != e) {
		p = p->next;
	}
	return p;
}
  • 根据指定数据获取该数据位置序号
int LElem_XL(LinkList L, ElemType e) {
	LinkList p = L->next;
	int i = 1;
	while (p && p->data != e) {
		p = p->next;
		++i;
	}
	if (!p) 
		return ERROR;
	else
		return i;
}

插入——在第i个结点前插入值为e的新结点

Status ListInsert_L(LinkList* L, int i, ElemType e) {
	Lnode* s;
	s = (LinkList)malloc(sizeof(Lnode));
	if (!s) /* 存储分配失败 */
		return ERROR;
	s->data = e;
	Lnode* p = *L;
	int j = 0;
	while (p && j < i - 1) {
		p = p->next;
		++j;
	}
	if (!p || j > i - 1) {
		return ERROR;
	}
	s->next = p->next;
	p->next = s;
	return OK;
}

删除——删除第i个结点并用e存储

Status ListDelete_L(LinkList* L, int i, ElemType* e) {
	LinkList p = (*L);
	int j = 0;
	while (p->next && j < i - 1) {//从首元结点开始
		p = p->next;
		++j;
	}
	if (!(p->next) || j > i - 1)//防止输入i下限不合理
		return ERROR;
	Lnode* s;
	s = p->next;
	*e = s->data;
	p->next = s->next;
	free(s);
	return OK;
}

建立单链表

  • 头插法——元素插入在链表头部,也叫前插法
void CreateList_H(LinkList* L, int n) {
	*L = (LinkList)malloc(sizeof(Lnode));
	if (!(*L)) /* 存储分配失败 */
		return;
	(*L)->next = NULL;
	Lnode* p;
	for (int i = n; i > 0; i--) {
		p = (LinkList)malloc(sizeof(Lnode));
		if (!p) /* 存储分配失败 */
			return ;
		p->data = i;
		p->next = (*L)->next;
		(*L)->next = p;
	}
}
  • 尾插法——元素在链表尾部,也叫后插法
void LCreateList_R(LinkList* L, int n) {
	*L = (LinkList)malloc(sizeof(Lnode));
	if (!(*L)) /* 存储分配失败 */
		return ;
	(*L)->next = NULL;
	Lnode* r = (*L);//尾指针r指向头结点
	Lnode* p;
	for (int i = n; i > 0; i--) {
		p = (LinkList)malloc(sizeof(Lnode));
		if (!p) /* 存储分配失败 */
			return;
		p->data = i;
		p->next = NULL;
		r->next = p;
		r = p;//r指向新的尾结点
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值