【数据结构】链表的基本操作

1.单链表的定义

线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数元素。
单链表结点结构如下图1.1所示,其中data为数据域,用来存放数据元素;next为指针域,存放其后继结点的地址。
在这里插入图片描述
单链表中结点类型描述如下:

typedef struct LNode{ //定义单链表结点类型
	ElemType data; //数据域
	LNode *next; //指针域 
} *LinkList;

通常利用头指针来标识一个单链表,如单链表L,头指针为NULL是表示一个空表。此外,为了操作上的方便,在单链表第一个节点之前附加一个结点,称为头结点。头结点的数据域可以不存放任何信息。如图1.2所示。
在这里插入图片描述

2.单链表上的基本操作

2.1采用头插法建立单链表

该方法从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后新结点插入到当前链表的表头,即头结点之后。如图1.3所示。
在这里插入图片描述

头插法建立单链表的算法如下:

LinkList HairInsert(LinkList &L,int n){  //n为所要创建链表的长度
	L = new LNode;  //创建头结点 
	L->next = NULL;  //初始化为空链表
	LinkList p;
	int x;
	for(int i = 0;i<n;i++){
		p = new LNode; // 创建新节点
		cin >> x; //输入结点的值
		p->data = x;
		p->next = L->next;  //将新结点插入表中
		L->next = p;
	}
	return L; 
} 

注意:采用头插法建立单链表时,读入数据的顺序与生成链表中的元素的顺序生成是相反的。该算法的时时间复杂度为O(n)

2.2采用尾插法建立单链表

头插法建立单链表的算法虽然简单,但生成链表中的结点的次序和输入数据的顺序不一致。而尾插法解决了这种问题,该方法将新结点插入到当前链表的表尾,所以必须增加一个尾指针r,使其始终指向当前链表的表尾,如图1.4所示。
在这里插入图片描述

尾插法建单链表的算法如下:

LinkList TailInsert(LinkList &L,int n){//n为所要创建链表的长度
	L = new LNode; // 创建头结点
	LNode *p,*r; // 其中r为尾指针
	r = L;
	ElemType x;
	for(int i = 0;i<n;i++){
		p = new LNode;  //创建新节点
		cin >> x;
		p->data = x;
		r->next = p;
		r = p; 
	} 
	r->next = NULL;
	return L;
} 

注意:尾插法的时间复杂度与头插法相同

2.3按序号查找结点数据

在单链表中从第一个结点出发,顺指针next域逐个网下搜索,直到找到第i个结点为止,否则返回最后一个指针域NULL.

按序查找的算法如下:

LNode *GetElem(LinkList &L,int i){  /*这里需要注意的是,因为用LNode 创建的头结点,
所以返回类型应为LNode(为指针类型),而不是LinkList  */
	LinkList p;
	p = L->next; //让指针p指向第一个节点
	int j = 1; //从第一个节点开始计数 
	//判断i的合法性 
	if(i<0) return NULL;
	if(i == 0) return L;
	while(p&&j<i){
		p = p->next;
		j++;
	}
	return p;  //返回指向第i个结点的指针,若i大于表长,则返回NULL
} 

注意:按序查找的时间复杂度为O(n)

2.4按值查找表结点

从单链表的第一个结点开始,由前往后依次比较表中各结点数据域的值,若某结点数据域的值等于给定值e,则返回该节点的指针;若整个单链表中没有这样的结点,则返回NULL.

按值查找的算法如下:

int LocateList(LinkList &L,ElemType e){
	LinkList p;
	p = L->next; //还是从第一个节点开始查找
	int j=1;
	while(p&&p->data!=e){  //从第i个结点开始查找data域为e的结点
		p = p->next;
		j++;
	} 
	return j;
} 

注意:按值查找操作的时间复杂度为O(n)

2.5插入节点操作

插入结点操作将值为x的新结点插入到单链表的第i
个位置上。先检查插入位置的合法性,然后找到待插入位置的前驱节点,即第i-1个结点,再往后插入新节点。算法首先调用按序号查找算法GetElem(L,i-1),查找第i-1个结点。设返回第i-1个结点为*p ,然后令新节点 *s的指针域指向 *p的后继节点,然后在令结点 *p的指针域指向新插入的结点 *s。如图1.5所示。
在这里插入图片描述

插入节点操作的算法如下:

LinkList InsertList(LinkList &L,int i,ElemType e){ //在第i个位置上插入元素e 
	LNode *p;
	LinkList s;
	p = GetElem(L,i-1);//获取第i个位置的前驱节点,并被p所指
	s = new LNode;
	s->data = e;
	s->next = p->next;
	p->next = s;
	return L;
}

注意:由于要调用查找算法GetElem(L,i-1)查找第查找第i-1个元素,所以该算法的时间复杂度为O(n)

2.6删除节点操作

删除结点操作是将单链表的第i个结点删除。先检查删除位置的合法性,后查找表中第i-1个结点,即被删除结点的前驱结点,再将其删除。假设结点*p 为找到的被删除结点的前驱结点,要实现删除操作,仅需修改 *p的指针域,即将 *p的指针域next指向 *q的下一结点(或者 *p的指针域next直接指向 *q的下一结点)。如图1.6所示。
在这里插入图片描述

删除操作的算法如下:

LinkList DeleteList(LinkList &L,int i){
	LNode *p; //标记指针
	p = GetElem(L,i-1);
	p->next = p->next->next;
	return L;
}

注意:和插入算法一样,该算法的主要时间也在耗费在查找操作上,故时间复杂度为O(n)

3.代码演示

#include<iostream>
#include<algorithm>
#define ElemType int
using namespace std;
typedef struct LNode{
	ElemType data; //数据域
	LNode *next; //指针域 
} *LinkList;
//链表的初始化
void IniteList(LinkList &L){
	L = new LNode; //创建头结点 
	L->next = NULL;  //将头结点的指针域置空 
} 
//头插法创建单链表
LinkList HairInsert(LinkList &L,int n){
	L = new LNode;  //创建头结点 
	L->next = NULL;
	LinkList p;
	int x;
	for(int i = 0;i<n;i++){
		p = new LNode; // 创建新节点
		cin >> x;
		p->data = x;
		p->next = L->next;
		L->next = p;
	}
	return L; 
} 
//尾插法创建单链表
LinkList TailInsert(LinkList &L,int n){
	L = new LNode; // 创建头结点
	LNode *p,*r; // 其中r为尾指针
	r = L;
	ElemType x;
	for(int i = 0;i<n;i++){
		p = new LNode;  //创建新节点
		cin >> x;
		p->data = x;
		r->next = p;
		r = p; 
	} 
	r->next = NULL;
	return L;
} 
//按序查找操作
LNode *GetElem(LinkList &L,int i){  /*这里需要注意的是,因为用LNode 创建的头结点,
所以返回类型应为LNode(为指针类型),而不是LinkList  */
	LinkList p;
	p = L->next; //让指针p指向第一个节点
	int j = 1; //从第一个节点开始计数 
	//判断i的合法性 
	if(i<0) return NULL;
	if(i == 0) return L;
	while(p&&j<i){
		p = p->next;
		j++;
	}
	return p;
} 
//按值查找操作
int LocateList(LinkList &L,ElemType e){
	LinkList p;
	p = L->next; //还是从第一个节点开始查找
	int j=1;
	while(p&&p->data!=e){
		p = p->next;
		j++;
	} 
	return j;
} 
//链表的插入操作
LinkList InsertList(LinkList &L,int i,ElemType e){ //在第i个位置上插入元素e 
	LNode *p;
	LinkList s;
	p = GetElem(L,i-1);//获取第i个位置的前驱节点,并被p所指
	s = new LNode;
	s->data = e;
	s->next = p->next;
	p->next = s;
	return L;
}
//链表的删除操作
LinkList DeleteList(LinkList &L,int i){
	LNode *p; //标记指针
	p = GetElem(L,i-1);
	p->next = p->next->next;
	return L;
}
//打印输出链表中的值
void PrinteList(LinkList &L){
	LNode *p;
	p = L->next; //让p指向第一个节点
	cout << "当前链表中的元素为:";
	while(p){
		cout << p->data << " ";
		p = p->next; // 让p指向下一节点 
	} 
	cout << endl;
} 
//头插法 
void Hair(LinkList &L){
	int n;
	cout << "请输入创建链表的长度:";
	cin >> n;
	HairInsert(L,n);
	cout << "头插法建立"; 
	PrinteList(L);
}  
//尾插法
 void Tail(LinkList &L){
	int n;
	cout << "请输入创建链表的长度:";
	cin >> n;
	TailInsert(L,n);
	cout << "尾插法建立";
	PrinteList(L);
}  
//按序查找
void Get(LinkList &L){
	int i;
	cout << "请输入要查找的位置:";
	cin >> i;
	LNode *p; //标记指针 
	p = GetElem(L,i);
	cout << "链表中第" << i << "个位置的元素为" << p->data << endl;  
} 
//按值查找
void  Locate(LinkList &L){
	ElemType e;
	cout << "请输入要查找的值:";
	cin >> e;
	cout << e << "在链表中的位置为:" << LocateList(L,e) << endl;
}
//插入
void Insert(LinkList &L){
	int i;
	ElemType e;
	cout << "请输入插入的位置和所插元素:";
	cin >> i >> e;
	InsertList(L,i,e); 
	cout << "插入后";
	PrinteList(L);
} 
//删除
void Delete(LinkList &L){
	int i;
	cout << "请输入要删除的位置:";
	cin >> i;
	DeleteList(L,i);
	cout << "删除后";
	PrinteList(L); 
} 
int main(){
	LinkList L;
	cout << "----------------1.链表的初始化        "<<  "2.头插法建立单链表------------------\n";
	cout << "----------------3.尾插法建立单链表    " << "4.按序查找--------------------------\n";
	cout << "----------------5.按值查找            " << "6.链表的插入操作--------------------\n";
	cout << "----------------7.链表的删除操作      " << "8.打印链表--------------------------\n" ;
	int i;
	cout << "请输入您所选择的操作:";
	for(int j=0;j<8;j++){
		cin >> i;
		switch(i){
		case 1: IniteList(L); break;
		case 2: Hair(L); break;
		case 3: Tail(L); break;
		case 4: Get(L); break;
		case 5: Locate(L); break;
		case 6: Insert(L); break;
		case 7: Delete(L); break;
		case 8: PrinteList(L); break; 
	}
	}
	return 0;
}

4.编译结果

在这里插入图片描述
总结:单链表的基本操作就写到这了,如果觉得有帮助,还请麻烦您的小手支持一下博主哦,谢谢!!由于水平有限,如有问题,欢迎评论区留言。

  • 38
    点赞
  • 220
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是C语言链表基本操作的代码示例: ```c #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node *next; }; struct Node* create_node(int data) { struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); new_node->data = data; new_node->next = NULL; return new_node; } void add_node(struct Node** head, int data) { struct Node* new_node = create_node(data); if (*head == NULL) { *head = new_node; return; } struct Node* current_node = *head; while (current_node->next != NULL) { current_node = current_node->next; } current_node->next = new_node; } void delete_node(struct Node** head, int data) { struct Node* current_node = *head; struct Node* prev_node = NULL; while (current_node != NULL && current_node->data != data) { prev_node = current_node; current_node = current_node->next; } if (current_node == NULL) { return; } if (prev_node == NULL) { *head = current_node->next; } else { prev_node->next = current_node->next; } free(current_node); } void print_list(struct Node* head) { struct Node* current_node = head; while (current_node != NULL) { printf("%d ", current_node->data); current_node = current_node->next; } printf("\n"); } int main() { struct Node* head = NULL; add_node(&head, 5); add_node(&head, 10); add_node(&head, 15); add_node(&head, 20); print_list(head); delete_node(&head, 15); print_list(head); delete_node(&head, 5); print_list(head); return 0; } ``` 以上是一个简单的链表实现,包括了节点创建、添加、删除以及遍历链表并打印数据的操作。请注意,这只是一个示例代码,实际应用时需要根据具体问题进行适当的修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值