数据结构(二)链表的相关操作

以下是我在学习 链表 及其相关接口操作时写的代码:

1.函数定义的 .c 文件

#include "LinkedList.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//1.初始化 / 销毁
void LListInit(LList *llist) {
	llist->first = NULL;
}
//2.头插
void LListPushFront(LList *llist, LLDataType v) {
	Node *node = (Node *)malloc(sizeof(Node));	//申请新结点
	node->value = v;
	node->next = llist->first;		//更改链表的关系
	llist->first = node;			//考虑空链表和非空链表都是一样的处理
}
//3.尾插
void LListPushBack(LList *llist, LLDataType v){
	Node *node = (Node *)malloc(sizeof(Node));		//申请新节点
	node->value = v;
	node->next = NULL;
	if (llist->first == NULL){
		llist->first = node;
	}
	else{
		Node *p = llist->first;
		while (p->next != NULL){		//找原来链表的最后一个结点
			p = p->next;
		}
		p->next = node;
	}
}
//4.头删
void LListPopFront(LList *llist) {
	assert(llist->first != NULL);		//排除掉链表中一个结点都没有的情况
	Node *save = llist->first->next;	//保存下一跳地址
	free(llist->first);					//释放第一个节点
	llist->first = save;				//将链表头指向保存的地址
}
//5.尾删
void LListPopBack(LList *llist) {
	assert(llist->first != NULL);		//排除掉链表中一个结点都没有的情况
	if (llist->first->next == NULL){	//只有一个结点
		free(llist->first);				//释放该节点
		llist->first = NULL;			//将链表头指向空
		return;
	}
	else{
		Node *p = llist->first;
		while (p->next->next != NULL){	//找倒数第二个结点
			p = p->next;
		}
		free(p->next);				//p指向倒数第二个节点,则p->next指向最后一个节点
		p->next = NULL;
	}
}
//6.在pos后面插入
void LListPosAfter(LList *llist, Node *pos, LLDataType v){
	Node *node = (Node *)malloc(sizeof(Node));
	node->value = v;
	node->next = pos->next;
	pos->next = node;
}
//7.在pos后删
LListEraseAfter(LList *llist, Node *pos){
	Node *save = pos->next->next;
	free(pos->next);
	pos->next = save;
}
//8.按值查找
Node *LListFind(LList *llist, LLDataType v){
	Node *p = llist->first;
	/*while (p != NULL){
		if (p->value == v){
			return p;
		}
		p = p->next;
	}*/
	for (p = llist->first; p != NULL; p = p->next){
		if (p->value == v){
			return p;
		}
	}
	return NULL;
}
//9.按值改
void LListModify(LList *llist, LLDataType v, LLDataType m){
	if (llist->first == NULL){
		return;
	}
	Node *p = llist->first;
	while (p->next != NULL){
		if (p->value == v){
			p->value = m;
		}
		p = p->next;
	}
}
//10.按值删除第一个
void LListRemove(LList *llist, LLDataType v){
	if (llist->first == NULL){
		return;
	}
	Node *p = llist->first;
	if (p->value == v){		//如果第一个节点为v,则头删
		LListPopFront(llist);
	}
	else{
		while (p->next != NULL){
			if (p->next->value == v){
				Node *save = p->next;		//保存一下需要删除的空间的地址
				p->next = p->next->next;	//将删除的后一个节点的首地址链接到前面
				free(save);			//如果不用free()释放删除的空间,则会导致内存泄漏
				return;
			}
			p = p->next;
		}
	}
}
//11.按值删除所有
void LListRemoveAll(LList *llist, LLDataType v){
	if (llist->first == NULL){
		return;
	}
	Node *p = llist->first;
	while (p->next != NULL){
		if (p->next->value == v){
			Node *save = p->next;
			p->next = p->next->next;		//因为 p 已经改变,所以用 else
			free(save);
		}
		else{
			p = p->next;
		}
	}
	if (llist->first->value == v){			//最后检查第一个节点是否需要删除,从而避免反复检查头结点
		LListPopFront(llist);
	}
}
//12.链表翻转
void LListReverse(LList *llist) {
	Node *result = NULL;
	Node *p = llist->first;
	while(p != NULL ){
		Node *save = p->next;			//保存下一节点的地址
		p->next = result;				//让当前节点第一次指向 NULL, 再次进来就指向了 p
		result = p;						//保存当前节点的地址
		p = save;						//p中存放下一节点的地址
	}
	llist->first = result;				//翻转成功后将头结点的地址给 llist->first
}
//13.打印
void LListPrint(const LList* llist){
	Node *p = llist->first;
	while(p != NULL){
		printf("%d  ", p->value);
		p = p->next;
	}
	printf("\n");
}

2.函数声明的 .h 头文件

#pragma once

typedef int LLDataType;

// 链表中的一个结点
typedef struct Node {
	LLDataType value;	// 值
	struct Node *next;		// 下一个结点的地址
} Node, *NodePointer;
// Single List
typedef struct LList {
	Node *first;	// *head;		第一个结点的地址
} LList;

// 初始化 / 销毁
void LListInit(LList *llist);

//1.增
//头插
void LListPushFront(LList *llist, LLDataType v);
//尾插
void LListPushBack(LList *llist, LLDataType v);
//在pos后面插入
void LLisPosAfter(LList *llist, Node *pos, LLDataType v);

//2.删
//头删
void LListPopFront(LList *llist);
//尾删
void LListPopBack(LList *llist);
//在pos后删
LListEraseAfter(LList *llist, Node *pos);
//按值删除第一个
void LListRemove(LList *llist, LLDataType v);
//按值删除所有
void LListRemoveAll(LList *llist, LLDataType v);

//3.改
//按值改
void LListModify(LList *llist, LLDataType v, LLDataType m);

//4.查
//按值查找
Node *LListFind(LList *llist, LLDataType v);

//5.链表翻转
void LListReverse(LList *llist);
//6.打印
void LListPrint(const LList* llist);

3.主函数 Main.c 文件

/*******************************链表********************************/
#include "LinkedList.h"
#include <stdlib.h>

void Test2(){
	LList llist;
	// 初始化 / 销毁
	LListInit(&llist);
	//头插
	LListPushFront(&llist, 10);
	LListPushFront(&llist, 20);
	LListPushFront(&llist, 30);
	LListPushFront(&llist, 40);
	LListPushFront(&llist, 50);//50,40,30,20,10
	//尾插
	LListPushBack(&llist, 1);
	LListPushBack(&llist, 2);
	LListPushBack(&llist, 3);
	LListPushBack(&llist, 4);
	LListPushBack(&llist, 5);//50,40,30,20,10,1,2,3,4,5
	//头删
	LListPopFront(&llist);//40,30,20,10,1,2,3,4,5
	//尾删
	LListPopBack(&llist);//40,30,20,10,1,2,3,4
	//在pos后面插入
	//LListPosAfter(&llist, 地址, v);//输入地址在地址处插入
	//在pos后删
	//LListEraseAfter(&llist, 地址);
	//按值查找
	printf("查: %p\n", LListFind(&llist, 3));//输出地址
	//按值改
	LListModify(&llist, 1, 2);//40,30,20,10,2,2,3,4
	//按值删除第一个
	LListRemove(&llist, 3);//40,30,20,10,2,2,4
	//按值删除所有
	LListRemoveAll(&llist, 2);//40,30,20,10,4
	//链表翻转
	LListReverse(&llist); //4,10,20,30,40
	//打印
	LListPrint(&llist);
}


int main() {
	Test2();

	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值