c语言练习89:链表的使用

链表的使用

虽然有这么多的链表的结构,但是我们实际中最常⽤还是两种结构: 单链表 和 双向带头循环链表 1. ⽆头单向⾮循环链表:结构简单,⼀般不会单独⽤来存数据。实际中更多是作为其他数据结 构的⼦结构,如哈希桶、图的邻接表等等。另外这种结构在笔试⾯试中出现很多。 2. 带头双向循环链表:结构最复杂,⼀般⽤在单独存储数据。实际中使⽤的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以后会发现结构会带 来很多优势,实现反⽽简单了,后⾯我们代码实现了就知道了。

补充说明:

1、链式机构在逻辑上是连续的,在物理结构上不⼀定连续

2、节点⼀般是从堆上申请的 3、从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

SList.h

cpp 复制代码
#pragma once
#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
//定义链表节点的结构
typedef int SLDataType;
typedef struct SListNode{
	int data;//要保存的数据
	struct SListNode* next;
}SLNode;
//创建节点组成链表并打印链表
void SLPrint(SLNode* phead);
//尾插
void SLPushBack(SLNode** pphead, SLDataType x);
void SLPushFront(SLNode** pphead, SLDataType x);
//尾删
void SLPopBack(SLNode** pphead);
void SLPopFront(SLNode** pphead);
//在指定位置之前插入数据
void SLInit(SLNode** pphead, SLNode* pos, SLDataType x);
//在指定位置之后插入数据
void SLInit(SLNode* pos, SLDataType x);
//找节点(考虑第一个参数为一级指针还是二级指针)
//因为不改变头节点,所以可以传一级指针
//但由于代码一致性原则(保持接口一致性),应该传二级指针
void SLFind(SLNode** pphead, SLDataType x);
//删除pos结点
void SLErase(SLNode** pphead, SLNode* pos);
//删除pos之后的结点
void SLEraseAfter(SLNode** pphead, SLNode* pos);
//销毁链表
void SLDesTory(SLNode** pphead);

SList.c

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS 
#include "SList.h"
void SLPrint(SLNode* phead) {
	//循环打印、
	SLNode* pcur = phead;
	while (pcur) {
		printf("%d ->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}

SLNode* SLBuyNode(SLDataType x) {
	SLNode* node = (SLNode*)malloc(sizeof(SLNode));
	node->data = x;
	node->next = NULL;
	return node;
}
//尾插
void SLPushBack(SLNode** pphead, SLDataType x) {
	assert(pphead);
	SLNode* node = SLBuyNode(x);
	if (*pphead = NULL) {
		*pphead = node;
		return;
	}
	//链表不为空,找尾(定义一个临时变量pcur)
	SLNode* pcur= *pphead;
	while (pcur->next) {
		pcur = pcur->next;
	}
	pcur->next = node;
}
void SLPushFront(SLNode** pphead, SLDataType x) {
	assert(pphead);
	SLNode* node = SLBuyNode(x);
	//新节点跟头结点连接起来
	node->next = *pphead;//plist
	//让新的节点成为头结点
	*pphead = node;
}
void SLPopBack(SLNode** pphead) {
	assert(pphead);
	//第一个节点不能为空
	assert(*pphead);
	//只有一个节点的情况
	if ((*pphead)->next==NULL) {
		//直接删除头结点
		free(*pphead);
		pphead = NULL;
		return;
	}
	//有多个结点的情况
	//找到尾结点的前一个节点
	SLNode* prev = NULL;
	SLNode* ptail = *pphead;
	while (ptail->next != NULL) {
		prev = ptail;
		ptail = ptail->next;
	}
	//prev的next指针不在指向ptail,而是指向ptail的下一个节点
	prev->next = ptail->next;
	free(ptail);
	ptail = NULL;
}
void SLPopFront(SLNode** pphead) {
	assert(pphead);
	assert(*pphead);
	SLNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
	del = NULL;
}
void SLInit(SLNode** pphead, SLNode* pos, SLDataType x) {
	assert(pphead);
	SLNode* node = SLBuyNode(x);
	//处理没有结点的情况(约定链表不能为空+pos也不能为空)
	assert(pos);
	assert(*pphead);
	//处理只有一个结点+pos指向第一个结点(pos即为第一个结点)
	if ((*pphead)->next == NULL||pos==*pphead) {
		node->next = *pphead;
		*pphead = node;
		return;
	}
	//找pos的前一个节点
	SLNode* prev = *pphead;
	while (prev->next != NULL) {
		prev = prev->next;
	}
	prev->next = pos;
	pos->next = node;
}
//查找第一个为x的节点
void SLFind(SLNode** pphead, SLDataType x) {
	SLNode* pcur = *pphead;
	while (pcur) {
		if (pcur->data == x) {
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}
//删除pos结点
void SLErase(SLNode** pphead, SLNode* pos) {
	assert(pphead);
	assert(*pphead);
	assert(pos);
	if (pos == *pphead) {
		*pphead = (*pphead)->next;
		free(pos);
		return;
	}
	//找pos的前一个节点
	SLNode* prev = *pphead;
	while (prev->next!=pos) {
		prev = prev->next;
	}
	prev->next = pos->next;
	free(pos);
	pos=NULL;
}
//删除pos之后的结点
void SLEraseAfter(SLNode** pphead, SLNode* pos) {
	assert(pos && pos->next);
	SLNode* del = pos->next;
	free(del);
	del = NULL;
}
//销毁链表
void SLDesTory(SLNode** pphead) {
	assert(pphead);
	SLNode* pcur = *pphead;
	//循环删除
	while (pcur) {
		SLNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

test.c

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS 
//int removeElement(int* nums, int numsSize, int val) {
//	int src, dst;
//	while (src < numsSize) {
//		if (nums[src] == val) {
//			src++;
//		}
//		else {
//			nums[dst] = nums[src];
//			src++;
//			dst++;
//		}
//	}
//	return dst;
//}
//void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
//	int l1 = m - 1, l2 = n - 1;
//	int l3 = m + n - 1;
//	while (l1 >= 0 && l2 >= 0) {
//		if (nums1[l1] > nums2[l2]) {
//			nums1[l3--] = nums1[l1--];
//		}
//		else {
//			nums1[l3--] = nums2[l2--];
//		}
//	}
//	while (l2 >= 0) {
//		nums1[l3--] = nums2[l2--];
//	}
//}
#include"SList.h"
void slttest() {
	SLNode* node1 = (SLNode*)malloc(sizeof(SLNode));
	node1->data = 1;
	SLNode* node2 = (SLNode*)malloc(sizeof(SLNode));
	node2->data = 2;
	SLNode* node3 = (SLNode*)malloc(sizeof(SLNode));
	node3->data = 3;
	SLNode* node4 = (SLNode*)malloc(sizeof(SLNode));
	node4->data = 4;

	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;
	SLNode* plist = node1;
	SLPrint(plist);
}
int main() {
	slttest();
	return 0;
}
相关推荐
冷静 包容37 分钟前
C语言学习之 没有重复项数字的全排列
c语言·开发语言·学习
碳苯42 分钟前
【rCore OS 开源操作系统】Rust 枚举与模式匹配
开发语言·人工智能·后端·rust·操作系统·os
结衣结衣.1 小时前
C++ 类和对象的初步介绍
java·开发语言·数据结构·c++·笔记·学习·算法
学习使我变快乐1 小时前
C++:静态成员
开发语言·c++
TJKFYY1 小时前
Java.数据结构.HashSet
java·开发语言·数据结构
杰哥在此1 小时前
Python知识点:如何使用Multiprocessing进行并行任务管理
linux·开发语言·python·面试·编程
小白学大数据1 小时前
User-Agent在WebMagic爬虫中的重要性
开发语言·爬虫·http
ROBIN__dyc1 小时前
C语言基本概念
c语言·开发语言
学习使我变快乐3 小时前
C++:const成员
开发语言·c++
500了4 小时前
Kotlin基本知识
android·开发语言·kotlin