学习记录:第二章 线性表的链式存储_单链表_插入删除查找三种基本操作以及求表长(代码、图示、C++)


前言

本文给出了单链表_插入删除查找三种基本操作以及求表长_代码及相应图示助于理解,代码实现使用的是C语言在线工具。无概念解释,初学者建议配合书本食用。
【如果图片看不清楚,网页版是很清晰的。😦】


一、插入

1. 按位序插入(带头结点的单链表)

在单链表第 i 个位置插入元素 e 。只需要找到第 i -1 个结点,将新结点插入其后。

在这里插入图片描述
图示:

在这里插入图片描述
i 的 3 种位置:第一个、中间、最后一个。

在这里插入图片描述

由上图可以看出,
当 i<1,i 不合法【就是代码的第一个 if 条件判断】。
当 i=1,最好情况下的时间复杂度是O(1)。
当 i=length+1,最坏情况下时间复杂度是O(n),因为需要循环找到第 i-1个结点。
当 1< i <length+1,平均时间复杂度也是O(n),因为也要循环找到第 i-1个结点。
当 i>length+1,i 不合法【就是代码的第二个 if 条件判断】。

代码如下:

typedef struct LNode{
   			//定义单链表结点类型
	int data;					//每个结点存放一个数据元素
	struct LNode *next;			//指针指向下一个结点
}LNode, *LinkList;

//在第i个位置插入元素e(带头结点)
bool ListInsert(LinkList &L, int i, int e){
   
	if(i<1)  		//判断i是否合法,位序从1开始,如果i<1,不合法
		return false;
	LNode *p;  		//指针p指向当前扫描到的结点
	int j = 0;		//p指向当前第j个结点,j=0是头结点,所谓的第0个结点(不存数据)
	p = L;			//L指向头结点,p从头结点开始
	while(p!=NULL && j<i-1){
   	//循环找到第i-1个结点
		p = p->next;
		j++;
	}
	if(p==NULL)		//判断i是否合法,比如总共4个结点存储数据,那么最多插入到第5个位置,如果i=6,经过上述while循环后此时p==NULL,不合法
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;				//返回true代表插入成功
}

2. 按位序插入(不带头结点的单链表)

在单链表第 i 个位置插入元素 e 。只需要找到第 i -1 个结点,将新结点插入其后。

i 的 3 种位置:第一个、中间、最后一个。

但是如果 i 是第一个位置,因为不带头结点,也就是不存在所谓的 “第0个” 结点,因此插入第1个元素时,需要更改头指针L,需要单独加一段代码,如图:
(其余两种位置和带头结点的一样)

在这里插入图片描述

typedef struct LNode{
   			//定义单链表结点类型
	int data;					//每个结点存放一个数据元素
	struct LNode *next;			//指针指向下一个结点
}LNode, *LinkList;				

//在第i个位置插入元素e(不带头结点)
bool ListInsert(LinkList &L, int i, int e){
   
	if(i < 1)  		//判断i是否合法,位序从1开始,如果i<1,不合法
		return false;
	if(i == 1){
   		//插入第1个结点的操作与其他结点不同
		LNode *s = (LNode *)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L = s;		//头指针指向新结点
		return true;
	}
	LNode *p;  		//指针p指向当前扫描到的结点
	int j = 1;		//p指向当前第j个结点
	p = L;			//p从第一个结点开始(不是头结点)
	while(p!=NULL && j<i-1){
   	//循环找到第i-1个结点
		p = p->next;
		j++;
	}
	if(p == NULL)		//判断i是否合法
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;			//将结点s与p的下一个结点相连
	p->next = s;				//将结点s连到p之后
	return true;				//返回true代表插入成功
}

3. 在指定结点之后,插入一个结点

指定 p 结点,在这个结点之后插入一个结点元素 e。

代码如下,由于没有循环,所以时间复杂度是O(1)。

typedef struct LNode{
   			//定义单链表结点类型
	int data;					//每个结点存放一个数据元素
	struct LNode *next;			//指针指向下一个结点
}LNode, *LinkList;

//在p结点之后插入新结点元素e
bool InsertNextNode(LNode *p, int e){
   
	if(p == NULL)
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if(s == NULL)		//内存不足,分配失败,这个if也可以不加
		return false;
	s->data = e;
	s->next = p->next;
	p->next = s;		//将结点s连到p后
	return true;
}

这段代码很眼熟吧,其实就是ListInsert插入函数的这一部分:

在这里插入图片描述
于是可以封装为如下图:

在这里插入图片描述

4. 在指定结点之前,插入一个结点

指定 p 结点,在这个结点之插入一个结点元素 e。相当于在 p 的前驱结点后面插入一个结点。

由于单链表只能向后找,不能向前找,那如何找到 p 结点的前驱节点?

  • 办法一,传入头指针 L,从头开始遍历找到 p 的前驱结点 m,然后在 m 结点之后插入 e。这样也可以,但是需要循环,意味着时间复杂度为O(n)。
bool InsertPriorNode(LinkList L, LNode *p, ElemType e) //传入头指针L
/* 然后循环,查找p的前驱 */

  • 办法二,与其找 p 的上一个结点,不如创建一个新结点 s,把 s 插到 p 之后,然后对调 p 和 s(偷天换日了啊兄弟们),这不就相当于在 p 之前插入一个 s 吗,这样不用循环,所以时间复杂度是O(1)。代码如下:
typedef struct LNode{
   			//定义单链表结点类型
	int data;					//每个结点存放一个数据元素
	struct LNode *next;			//指针指向下一个结点
}LNode, *LinkList;

//在p结点之前插入新结点元素e
bool InsertPriorNode(LNode *p, ElemType e){
   
	if(p == NULL)
		return false;
	LNode *s = (LNode 
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
存储链表是一种常见的数据结构,以下是C语言实现链表插入删除查找求表、置逆以及有序链表的合并算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct Node { int data; struct Node* next; } Node; // 在链表插入一个节点 void insertNode(Node** head, int value) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = value; newNode->next = *head; *head = newNode; } // 从链表删除一个节点 void deleteNode(Node** head, int value) { Node* curr = *head; Node* prev = NULL; while (curr != NULL && curr->data != value) { prev = curr; curr = curr->next; } if (curr == NULL) { printf("Node not found.\n"); return; } if (prev == NULL) { *head = curr->next; } else { prev->next = curr->next; } free(curr); } // 在链表查找一个节点 Node* searchNode(Node* head, int value) { Node* curr = head; while (curr != NULL) { if (curr->data == value) { return curr; } curr = curr->next; } return NULL; } // 求链表度 int getLength(Node* head) { int length = 0; Node* curr = head; while (curr != NULL) { length++; curr = curr->next; } return length; } // 将链表置逆 void reverseList(Node** head) { Node* prev = NULL; Node* curr = *head; Node* next = NULL; while (curr != NULL) { next = curr->next; curr->next = prev; prev = curr; curr = next; } *head = prev; } // 合并两个有序链表 Node* mergeLists(Node* list1, Node* list2) { Node* mergedList = NULL; Node** tail = &mergedList; while (list1 != NULL && list2 != NULL) { if (list1->data <= list2->data) { *tail = list1; list1 = list1->next; } else { *tail = list2; list2 = list2->next; } tail = &((*tail)->next); } if (list1 != NULL) { *tail = list1; } else { *tail = list2; } return mergedList; } // 打印链表中的元素 void printList(Node* head) { Node* curr = head; while (curr != NULL) { printf("%d ", curr->data); curr = curr->next; } printf("\n"); } // 析构链表 void destroyList(Node** head) { Node* curr = *head; Node* next; while (curr != NULL) { next = curr->next; free(curr); curr = next; } *head = NULL; } int main() { Node* head = NULL; // 插入节点 insertNode(&head, 3); insertNode(&head, 2); insertNode(&head, 1); // 打印链表 printf("Linked List: "); printList(head); // 查找节点 Node* node = searchNode(head, 2); if (node != NULL) { printf("Found node with value %d\n", node->data); } else { printf("Node not found.\n"); } // 删除节点 deleteNode(&head, 2); // 打印链表 printf("Linked List after deletion: "); printList(head); // 求链表度 int length = getLength(head); printf("Length of Linked List: %d\n", length); // 置逆链表 reverseList(&head); // 打印链表 printf("Reversed Linked List: "); printList(head); // 析构链表 destroyList(&head); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值