数据结构:单向链表及其基本操作

1. 单向链表介绍

  1. 链表的定义:是一种物理存储结构上非连续、非顺序的存储结构,数据元素(结点)的逻辑顺序是通过链表中的指针链接次序实现的。
    注:结点包含两个域:数据域和指针域;
  2. 链表的特点
    1. 存储单元可以是可连续的,也可以是不连续的;
    2. 作插入和删除操作时,不需要移动元素,仅需修改指针;
    3. 不可随机存取;
  3. 单向链表:链表的每一个结点中只包含一个指针域,如下图所示:
    在这里插入图片描述

其中,单向链表的第一个结点之前附设的结点,称为头结点head;链表的结点位置从0开始,例如第一个结点在链表中所对应的位置pos=0.

2. 单向链表的基本操作(C/C++实现)

2.1 初始化

由以上图示可知,单向链表可由头指针唯一确定,在C语言中可用结构指针分别对单向链表结点和单向链表进行描述。

2.1.1 单向链表结点存储结构

typedef struct LINKNODE {
	void* data;    //void* :无类型指针,可以指向任何类型数据
	struct LINKNODE* next;
}LinkNode;

void*为无类型指针,其他任何类型都可以直接赋值给它,无需进行强转,但是反过来不可以。
2.1.2 单向链表的存储结构体

typedef struct LINKLIST {
	LinkNode* head;  //头结点
	int size;
	//没有容量的概念
}LinkList;

分别构造单向链表的结点和存储结构类型,首先申请内存空间创建链表,然后根据结点的数据结构类型进行头结点的创建,此时即可创建出唯一确定的单向链表。初始化链表代码如下所示:

LinkList* Init_LinkList() {
	//申请内存
	LinkList* list = (LinkList*)malloc(sizeof(LinkList));
	list->size = 0;

	//创建头结点,不保存数据信息
	list->head = (LinkNode*)malloc(sizeof(LinkNode));  //申请头结点内存
	list->head->data = NULL;
	list->head->next = NULL;
	return list;
}

其中,malloc()函数分配一块连续的内存,释放内存时利用free()函数进行释放;sizeof(LinkList)为malloc分配的内存大小,该处malloc()函数返回值为LinkList*。

2.2 单向链表的插入

与线性表和顺序存储结构不同,链表在进行插入和删除元素时,不需要移动大量元素,仅需修改指针即可实现。单向链表的插入操作可分为两步进行:1.创建辅助指针变量pCurrent,表示插入位置的前一个结点;2.新结点入链表。插入链表示意图如下:
在这里插入图片描述

pNext为新节点需要结点插入的位置,因此需要找到pNext结点的前一个结点,故创建辅助指针变量pCurrent表示pNext结点的前一个结点;newnode结点为需要插入元素的新节点。找到pCurrent后,只需要newnode->next = pCurrent->next;(令newnode指针指向下一个结点pNext),同时pCurrent->next = newnode;当前结点指针指向newnode结点,即可完成单向链表按位置插入操作。
具体实现代码如下:

//指定位置插入结点
void Insert_LinkList(LinkList* list, int pos,void* data) {
	if (list == NULL) {
		return ;
	}
	if (data == NULL) {
		return;
	}

	//友好的处理,pos越界
	if (pos<0||pos>list->size) {
		pos = list->size;
	}

	//创建新的节点,将数据赋值给结点
	LinkNode* newnode = (LinkNode*)malloc(sizeof(LinkNode));
	newnode->data = data;
	newnode->next = NULL;

	//按指定位置插入
	//1.创建辅助指针变量,找到插入位置前一个结点
	LinkNode* pCurrent = list->head;
	for (int i = 0; i < pos;i++) {
		pCurrent = pCurrent->next;
	}
	//2.新节点入链表
	newnode->next = pCurrent->next;
	pCurrent->next = newnode;

	list->size++;
}

其中,LinkNode* pCurrent = list->head;为辅助指针变量,旨在找到插入位置的前一个结点;LinkNode* newnode = (LinkNode*)malloc(sizeof(LinkNode));为存储待入链表数据的结点。

2.3 单向链表的删除

如下图所示,在单向链表中删除元素pDel,仅需找到pDel的前一个结点pCurrent并修改结点pCurrent的指针域,使pCurrent指向下一个结点即可。修改指针语句为:pCurrent->next = pDel->next;
在这里插入图片描述
具体代码实现如下:

//删除指定位置的值
void RemoveByPos_LinkList(LinkList* list, int pos) {
	if (list == NULL) {
		return ;
	}

	if (pos < 0 || pos >= list->size) {
		return;
	}

	//创建辅助指针变量找到删除的前一个结点
	LinkNode* pCurrent = list->head;
	for (int i = 0; i < pos;i++) {
		pCurrent = pCurrent->next;
	}

	//缓存删除的结点
	LinkNode* pDel = pCurrent->next;
	pCurrent->next = pDel->next;
	//释放删除结点的内存
	free(pDel);
	list->size--;
}

2.4 单向链表的元素查找

查找链表中是否存在元素data,仅需对链表进行遍历即可。1.创建辅助指针pCurrent对链表遍历;2.遍历查找,直到找到第i个元素data,返回i,或者pCurrent指向空,遍历结束。

//查找
int Find_LinkList(LinkList* list, void* data) {
	if (list == NULL) {
		return -1;
	}
	if (data == NULL) {
		return -1;
	}
	
	//遍历查找
	LinkNode* pCurrent = list->head->next;   //pCurrent指向链表的第一个结点
	int i = 0;
	while (pCurrent != NULL) {
		if (pCurrent->data == data) {
			break;
		}
		i++;
		pCurrent = pCurrent->next;
	}
	return i;
}

2.4 单向链表的内存释放

//释放链表内存
void FreeSpace_LinkList(LinkList* list) {
	if (list == NULL) {
		return;
	}

	//1.创建辅助指针变量
	LinkNode* pCurrent = list->head;

	while (pCurrent != NULL) {
		//每次均创建当前结点的下一个结点进行缓存
		LinkNode* pNext = pCurrent->next;
		free(pCurrent);
		pCurrent = pNext;
	}
	//释放链表内存
	list->size = 0;
	free(list);
}

以上仅为本人学习过程中的笔记记录,有错误和不足之处希望大家指出~

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++中的链表是一种常见的数据结构,它由多个节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。链表有很多种类型,包括单向链表、双向链表和循环链表等。 以下是链表基本操作: 1. 创建链表节点 链表节点通常由两个部分组成:数据和指向下一个节点的指针。我们可以定义一个结构体来表示节点: ```c++ struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; ``` 这个结构体包含一个整数和一个指向下一个节点的指针,其中构造函数用于初始化节点的。 2. 插入节点 插入节点是链表中最基本的操作之一。我们可以将新节点插入链表的任何位置,包括链表的头部、尾部或中间。 ```c++ void insertNode(ListNode*& head, int val) { ListNode* newNode = new ListNode(val); newNode->next = head; head = newNode; } ``` 这个函数将创建一个新节点并将其插入链表的头部。 3. 删除节点 删除节点也是链表中最基本的操作之一。我们可以从链表的任何位置删除节点,包括链表的头部、尾部或中间。 ```c++ void deleteNode(ListNode*& head, int val) { if (head == NULL) return; if (head->val == val) { ListNode* temp = head; head = head->next; delete temp; return; } ListNode* prev = head; ListNode* curr = head->next; while (curr != NULL) { if (curr->val == val) { prev->next = curr->next; delete curr; return; } prev = curr; curr = curr->next; } } ``` 这个函数将从链表中删除具有指定的节点。 4. 遍历链表 遍历链表是查看链表中节点的一种方法。 ```c++ void traverseList(ListNode* head) { ListNode* curr = head; while (curr != NULL) { cout << curr->val << " "; curr = curr->next; } } ``` 这个函数将遍历整个链表,并输出每个节点的。 这些是链表基本操作。在实际的应用程序中,我们可能需要使用更多的操作来实现特定的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

良辰与日月

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

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

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

打赏作者

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

抵扣说明:

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

余额充值