链表的基本操作,用链表实现线性表

链表

增删改查指针指向等于地址赋值定义一个链表结构体

复制代码
typedef struct _NODE_ {
	int number;
	struct _NODE* next; 
}Node,*Lintlist;

这里的node是对节点命名时的数据类型Linklist是对该链表命名时的数据类型初始化

1.建立一个链表

2.申请一个头节点

复制代码
Linklist init(Linklist l) {
	Node* head = (Node*)malloc(sizeof(Node));
	if (head == NULL) {
		printf("内存分配失败");
		return NULL;
	}
	head->next = NULL;
	return head;
}

在主函数中调用是

复制代码
Linklist l=NULL;
l = init(l);

也可以Linklist l=init(l);

当然在这里也可以这样来在这里函数的参数有没有都可以,因为其本质要的是申请的这个节点的地址也就是head的值在主函数中他会把这个返回值赋值给l;包括这里的函数类型也可以换成Node*如下

复制代码
Node* init() {
	Node* head = (Node*)malloc(sizeof(Node));
	if (head == NULL) {
		printf("内存分配失败");
		return NULL;
	}
	head->next = NULL;
	return head;
}

在主函数中调用就是Linklist l=init();

增加操作分为三种,分别为头插法,尾插法,以及在指定位置增加,这里分为三种操作的一个原因就是增加可读性还有一个原因是这样能帮助我们写代码不需要判断各种临界情况代码不会复杂,相对简单。

头插法

复制代码
Linklist head_add(Linklist l, int m) {
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("内存分配失败");
		return l;
	}
	s->next = l->next;
	s->number = m;
	l->next = s;
	return l;
}

在这里有两个点需要注意第一点,头指针的指针域数值在改变的时候不能让链表断裂,比如

复制代码
l->next = s;
s->next = l->next;

在这里我们先让头指针的指针域指向了s但这里就会导致一个问题,我们原本在这个指针域里面存储的地址丢了我们再执行s->next = l->next;就会 让s的next指向自己就会导致后续链表的断裂所以我们在改变链表的指针域时,最重要的就是不能让链表断裂,即不能让数据丢失

第二点在返回值上,我们其实可以让返回值为void因为在这个函数里面其实我们没有动l的值l里面是一个指针,而这个指针指向了一个我们声明的结构体类型的数据我们是根据这个指针访问这个结构体类型的数据,然后更改这个结构体内的一些数据我们并没有对l这个变量里面存储的数据进行改变所以我们可以用void而在上面我们用Link list这个作为返回值的原因是在我们对l的理解中,l指的是这个链表对于这个链表实际上是发生了变化的所以我们在这里用了返回值接下来的尾插法和指定位置插入都有这个问题。

尾插法

1.找到未节点

2.构建一个节点插在为节点后面

复制代码
Linklist rear_add(Linklist l, int m) {
	Node* p = l;
	while (p->next) {
		p = p->next;
	}
	
	
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("内存分配失败");
		
		return l;
	}
	s->number = m;
	s->next = NULL;
	p->next = s;
	return l;
}

指定位置插入

1.找到指定位置(这里可以来一个find函数)接下来的操作是基于find函数进行的find函数在后面紧挨着

2.通过find函数的返回值确认后续操作

3,如果是NULL则没有找的该数据,无法执行插入操作

4.找到之后,就构建新的节点插入

复制代码
Linklist rear_add(Linklist l, int m) {
	Node* p = l;
	while (p->next) {
		p = p->next;
	}
	
	
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("内存分配失败");
		return l;
	}
	s->number = m;
	s->next = NULL;
	p->next = s;
	return l;
}

查,找到指定数据的节点,然后根据查找结果确定返回值

复制代码
Node* find(Linklist l, int k) {
	
	Node* q = l->next;
	while (q && q->number != k) {
	
		q = q->next;
	}
	return q;
}

删,删除指定数据,在这里不能通过查找函数,是因为在删除操作里我们要涉及前面的一个节点的指针域在双向链表中就可以通过find函数进行查找了,因为在双向链表中,节点内包含着前节点的地址

复制代码
Linklist delet(Linklist l, int k) {
	//k为删减的值
	Node* p = l;
	Node* q = l->next;
	while (q && q->number != k) {
		p = q;
		q = q->next;
	}
	if (q==NULL) {
		printf("未找到该数据,不能执行删除操作\n");
		return l;
	}
	p->next = q->next;
	
	free(q);
	q = NULL;
	return l;
}

改,最简单的操作,可以选择通过find函数也可以直接查找,因为这个函数不涉及指针的改变

复制代码
Linklist change(Linklist l, int k,int m) {
	Node* p = find(l, k);
	if (p == NULL) {
		printf("未找到该数据,不能实行数据更改操作\n");
		return l;
	}
	p->number = m;
	return l;
}

输出函数输出链表值

复制代码
void printff(Linklist l) {
	Node* p = l->next;
	while (p) {
		printf("%d ", p->number);
		p = p->next;
	}
	printf("\n");
}

下面时主函数的调用

复制代码
int main() 
{
	Linklist l=NULL;
	l = init(l);
	l = head_add(l, 3);
	l = head_add(l, 9);
	l = head_add(l, 5);
	printff(l);
	l = rear_add(l, 8);
	l = rear_add(l, 4);
	l = rear_add(l, 6);
	printff(l);
	l = inadd(l,3, 15);
	l = inadd(l, 10, 16);
	l = inadd(l, 9, 12);
	printff(l);
	l = delet(l, 4);
	l = delet(l, 8);
	l = delet(l, 16);
	printff(l);
	l = change(l, 4, 43);
	printff(l);
	return 0;
}

文章转载自: ++爱偷懒的我++

原文链接: https://www.cnblogs.com/student-z/p/19376618

体验地址: http://www.jnpfsoft.com/?from=001YH

相关推荐
Darling噜啦啦5 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠6 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾6 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres8216 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q6 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒6 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
疯狂成瘾者6 天前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表
WL学习笔记6 天前
单项不带头不循环链表
数据结构·链表
小糯米6016 天前
JS 数组
数据结构·算法·排序算法
小欣加油6 天前
leetcode3612 用特殊操作处理字符串I
数据结构·c++·算法·leetcode·职场和发展