原来链表如此简单

由于顺序表(数组)的插入、删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储——单链表。单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻,所以单链表是非随机存取结构,不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从第一个结点开始遍历,依次查找。

单链表的基本构成

在这里插入图片描述

其中:data表示数据域,用于存放该结点的数据信息;next表示指针域,用于存放相邻下一结点的地址。

单链表中结点类型的描述如下:
struct LNode {
	int data;
	LNode* next;
};

单链表的基本操作

单链表的查找-按值进行查找

查找值x在单链表L中的结点指针(指针即地址)。

算法思想:从单链表的第一个结点开始,依次比较表中各个结点的数据域的值,若某结点数据域的值等于num,则返回该结点的指针;若整个单链表中没有这样的结点,则返回空。

按值查找结点值的算法如下:
LNode *LocateElem(LNode *L, int num) {
	LNode *p = L->next;
	while (p != NULL && p->data != num) {
		p = p->next;
	}
	return p;
}

单链表的查找-按位置进行查找

查找单链表L中第 i(i>0)个位置的结点指针。

算法思想:从单链表的第一个结点开始,顺着指针域逐个往下搜索,直到找到第 i 个结点为止,否则返回最后一个结点的指针域NULL。

按位查找结点值的算法如下:
LNode *GetElem(LNode *L, int i) {
	LNode *p = L->next;
	if (p == NULL) {
		return NULL;
	}
	int j = 1;
	while (p != NULL && j < i) {
		p = p->next;
		j++;
	}
	return p;
}

单链表的建立-头插法

所谓头插法建立单链表就是将新结点插入到当前链表的表头,即头结点之后。如图所示:

在这里插入图片描述

算法思想:首先初始化一个单链表,其头结点为空,然后循环插入新结点*p:将p的next指向头结点的下一个结点,然后将头结点的next指向p。

主要代码:
LNode *p = new LNode; //申请新结点p
p->data = x; //给新结点赋值,x是已知值
p->next = L->next; //将原头结点的next指针域值赋值给新结点next指针域
L->next = p; //将头结点连接到新结点
头插法建立单链表的算法如下:
LNode *HeadInsert() {
	LNode *L = new LNode;  //创建头结点
	L->next = NULL;  //初始时使头结点指向空
	int x;
	while (cin >> x) {
		LNode *p = new LNode;
		p->data = x;
		p->next = L->next;
		L->next = p;
	}
	return L;
}

需要指出的是,头插法建立的单链表中结点的次序和输入数据的顺序不一致,是相反的。若希望两者的顺序是一致的,则可采用尾插法建立单链表。

单链表的建立-尾插法

所谓尾插法建立单链表,就是将新结点插入到当前链表的表尾。如下图所示:

在这里插入图片描述

算法思想:首先初始化一个单链表,然后声明一个尾指针r,让r始终指向当前链表的尾结点,向单链表的尾部插入新的结点*p,将尾指针r的next域指向新结点,再修改尾指针r指向新结点,也就是当前链表的尾结点。最后别忘记插入所有结点之后,将尾结点的指针域置空。

主要代码:
LNode *p = new LNode; //申请新结点p
p->data = x; //给新结点赋值,x是已知值
r->next = p; //在原尾指针所指结点后插入新结点p
r = p; //插入新结点p后,更新尾指针的位置
尾插法建立单链表的算法如下:
LNode *TailInsert() {
	LNode *L = new LNode;
	L->next = NULL;
	int x;
	LNode *r = L;
	while (cin >> x) {
		LNode *p = new LNode;
		p->data = x;
		r->next = p;
		r = p;
	}
	r->next = NULL;
	return L;
}

单链表的插入

情况1:已知相邻结点中的一个(并且是插入后结点的前驱结点X)
在这里插入图片描述

插入步骤:
1.申请新结点p
2.给新结点p赋值
3.将原X结点的next域值赋值给新结点p的next域
4.将X结点连接到p,即将p赋值给X结点的next域

主要代码:
LNode *p = new LNode; //申请新结点p
p->data = x; //给新结点赋值,x是已知值
p->next = X->next; //将原X结点的next域值赋值给新结点p的next域
X->next = p; //X结点连接到p,即将p赋值给X结点的next域

情况2:已知两个相邻结点(前驱结点X,后继结点Y)
在这里插入图片描述

插入步骤:
1.申请新结点p
2.给新结点p赋值
3.将X结点连接到p,即将p赋值给X结点的next域
4.将p结点连接到Y,即将Y赋值给p结点的next域

主要代码:
LNode *p = new LNode; //申请新结点p
p->data = x; //给新结点赋值,x是已知值
X->next = p; //将X结点连接到p,即将p赋值给X结点的next域
p->next = Y; //将p结点连接到Y,即将Y赋值给p结点的next域

单链表的删除

将单链表的第 i 个结点删除。

算法思想:先检查删除位置的合法性,然后从头开始遍历,找到表中的第 i-1 个结点,即被删除结点的前驱结点p,被删除结点为q,修改p的指针域,将其指向q的下一个结点,最后再释放结点q的存储空间。

在这里插入图片描述

删除步骤:
1.将p结点指向原q结点的后驱,即将q结点的next域值赋值给p结点的next域
2.删除q结点,即调用free函数

主要代码:
从头开始遍历,找到表中的第 i-1 个结点(代码过程省略)
q->next = p->next; //将q结点的next域值赋值给p结点的next域
free(q); //删除q结点

后续更新《一章了解栈和队列》,各位看官,关注不迷路!!!

  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值