用C语言实现单链表

循环单链表的实现c语言 1.循环单链表和单链表的区别在于链表中最后一个结点的指针不是指向NULL,而是指向头结点,这样链表结点就形成了一个环。循环单链表是一个环,所以在链表中任意位置插入或者删除结点时都是等价的,不需要根据所操作结点是否是尾结点分类讨论,因此简化了代码。 2.下面是循环单链表的具体操作详细代码,由c语言实现。 #include<stdio.h> #include<malloc.h> #define ElemType int typedef struct LinkNode{ ElemTy 阅读详情

目录

1.链表的概念及结构

2.链表的分类

3.实现单链表

3.1头文件SList.h

3.2相关函数实现文件SList.c

 3.2.1创建节点和打印链表

3.2.1.1创建节点

3.2.1.2打印链表函数

3.2.2头部插入删除/尾部插入删除

3.2.2.1尾插 

3.2.2.2头插 

3.2.2.3尾删

3.2.2.4头删

3.2.3查找

 3.2.4对指定位置做增删操作

3.2.4.1在指定位置之前插入数据

3.2.4.2 删除pos节点

 3.2.4.3在指定位置之后插入数据

3.2.4.4删除pos之后的节点

3.2.5销毁链表

 3.3参考代码

4.顺序表和单链表的优缺点分析


1.链表的概念及结构

        概念:链表是一种物理存储结构上非连续、非顺序的存储结构,但是逻辑顺序是连续的存储结构。数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

        链表的结构跟火车车厢相似,只需要将火车里的某节车厢去掉/加上,不会影响其他车厢,每节车厢都是独立存在的。

        与顺序表不同的是,链表里的每节“车厢”都是独立申请下来的空间,称之为“节点/结点”。节点的组成主要有两个部分:当前节点要保存的数据和下一个节点的地址(指针变量)。 

         图中指针变量plist保存的是第一个节点的地址,我们称plist此时“指向”第一个节点,如果我们希望plist“指向”第二个节点时,只需要修改plist保存的内容为0x0012FFA0.

        链表中每个节点都是独立申请的(需要插入数据时才去申请一块节点的空间),我们需要通过指针变量来保存下一个节点位置才能从当前节点找到下一个节点。

        假设当前保存的节点为整形,则链表的节点结构如下:

         当我们想要保存⼀个整型数据时,实际是向操作系统申请了⼀块内存,这个内存不仅要保存整型数据,也需要保存下⼀个节点的地址(当下⼀个节点为空时保存的地址为空)。

        当我们想要从第⼀个节点⾛到最后⼀个节点时,只需要在前⼀个节点拿上下⼀个节点的地址(下⼀个节点的钥匙)就可以了。

补充说明:

        1.链式机构在逻辑上是连续的,在物理结构上不一定连续。

        2.节点一般是从堆上申请的。

        3.从堆上申请来的空间,是按照一定策略分配出来的,每次申请的空间可能连续,可能不连续。

2.链表的分类

        链表的结构非常多样,以下情况组合起来就有8种(2*2*2)链表结构:

         虽然有这么多的链表的结构,但是我们实际中最常用的还是两种结构:单链表和双向带头链表。

        1.无头单向非循环链表(单链表):结构简单,⼀般不会单独⽤来存数据。实际中更多是作为其他数据结构的⼦结构,如哈希桶、图的邻接表等等。

        2.带头双向循环链表:结构最复杂,⼀般⽤在单独存储数据。实际中使⽤的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以后会发现结构会带来很多优势,实现反⽽简单了。

3.实现单链表

3.1头文件SList.h

        头文件主要是包含整个项目所用到的其他头文件以及声明函数。

#pragma once

#include <stdio.h>
#include <stdlib.h>

typedef int SLTDataType;
typedef struct SListNode  //链表节点结构
{
	SLTDataType val;
	struct SListNode* next;
}SLTNode;

//创建节点
SLTNode* BuyNode(SLTDataType x);

//打印链表
void SLTPrint(SLTNode* phead);

//头部插入删除/尾部插入删除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

3.2相关函数实现文件SList.c

 3.2.1创建节点和打印链表

3.2.1.1创建节点

        函数实现:

SLTNode* BuyNode(SLTDataType x)
{
	SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode)); //申请一个节点的大小
	if (newNode == NULL)
	{
		perror("malloc fail!\n");
		exit(1);
	}

	newNode->val = x;     //将数据放入新申请的节点中
	newNode->next = NULL; //将新节点的next指针初始化指向NULL

	return newNode;
}
3.2.1.2打印链表函数

         函数实现:

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;    
	while (cur)
	{
		printf("%d->", cur->val);
		cur = cur->next;
	}
	printf("NULL\n");
}

        测试代码:

#include "SList.h"

void test()
{
	SLTNode* node1 = BuyNode(1);
	SLTNode* node2 = BuyNode(2);
	SLTNode* node3 = BuyNode(3);
	SLTNode* node4 = BuyNode(4);
	SLTNode* node5 = BuyNode(5);
	SLTNode* node6 = BuyNode(6);

	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = node6;

	SLTNode* s = node1;
	SLTPrint(s);
}

int main()
{
	test();
	return 0;
}

3.2.2头部插入删除/尾部插入删除

3.2.2.1尾插 

        函数实现:

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead); //下面要对pphead解引用,所以pphead不能为空
					//*pphead等同与指向头节点的指针,如果这个为空则
					//相当于为空链表,所以不用对*pphead进行断言
	//创建一个节点
	SLTNode* newnode = BuyNode(x);

	//空链表和非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//找尾
		SLTNode* ptail = *pphead;
		while (ptail->next)
		{
			ptail = ptail->next;
		}

		//在尾部进行插入
		ptail->next = newnode;
	}
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	SLTPrint(plist);
}

int main()
{
	test();
	return 0;
}

3.2.2.2头插 

        函数实现:

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);

	//创建一个节点
	SLTNode* newnode = BuyNode(x);

	//先将newnode->next指向之前的头节点,然后在将newnode作为新的头节点
	newnode->next = *pphead;
	*pphead = newnode;
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	SLTPushFront(&plist, 5); //头插

	SLTPrint(plist);
}

int main()
{
	test();
	return 0;
}

3.2.2.3尾删

        函数实现: 

void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	//链表不能为空链表
	assert(*pphead);

	//只有一个节点的情况和多个节点的情况
	if ((*pphead)->next == NULL) //只有一个节点
	{
		free(*pphead);
		*pphead = NULL;
	}
	else //多个节点
	{
		//找尾节点和尾节点前面的一个节点
		SLTNode* ptail = *pphead;
		SLTNode* prev = ptail; //prev表示尾节点的前面一个节点

		while (ptail->next)
		{
			prev = ptail; //将现在的尾节点给到prev
			ptail = ptail->next; //将尾节点的next变成新的尾节点
		}

		//删除尾节点
		free(ptail);
		prev->next = NULL;
	}
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	SLTPopBack(&plist);  //尾删
	SLTPopBack(&plist);


	SLTPrint(plist);
}

int main()
{
	test();
	return 0;
}

3.2.2.4头删

         函数实现:

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);

	SLTNode* del = *pphead; //先创建一个新的指针存储之前的头节点
	*pphead = (*pphead)->next;  //将头节点的下一个节点作为新的头节点
	free(del);        //删除之前的头节点
	del = NULL;
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	SLTPopFront(&plist);
	SLTPopFront(&plist);

	SLTPrint(plist);
}

int main()
{
	test();
	return 0;
}

3.2.3查找

        函数实现:

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;

	while (cur)
	{
		if (cur->val == x)
		{
			printf("找到了!\n");
			return cur;
		}
		cur = cur->next;
	}
	printf("没有找到!\n");
	return NULL;
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	//SLTPopFront(&plist);  //头删
	//SLTPopFront(&plist);

	SLTPrint(plist);

	SLTFind(plist, 5);

}

int main()
{
	test();
	return 0;
}

        将上述查找的数字“5”换为“2”. 

 3.2.4对指定位置做增删操作

3.2.4.1在指定位置之前插入数据

        函数实现:

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && *pphead);
    assert(pos);

	SLTNode* newnode = BuyNode(x);

	if (pos == *pphead)	//pos在第一个位置--头插入
	{
		SLTPushFront(pphead, x);  //头插
	}
	else //pos在中间和尾部
	{
		SLTNode* pcur = *pphead;
		SLTNode* prev = *pphead;
        //找到pos节点和pos前面的一个节点
		while (pcur != pos)
		{
			prev = pcur;
			pcur = pcur->next;
		}

		newnode->next = pcur; //将新节点的next指向pos
		prev->next = newnode; //将pos前一个节点的next指向新节点
	}
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	//SLTPopFront(&plist);  //头删
	//SLTPopFront(&plist);

	SLTNode* pos = SLTFind(plist, 2);

	SLTInsert(&plist, pos, 6); //在指定位置之前插入数据

	SLTPrint(plist);

}

int main()
{
	test();
	return 0;
}

3.2.4.2 删除pos节点

        函数实现:

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);

	if (*pphead == pos)
	{
		//删除第一个节点--头删
		SLTPopFront(pphead);
	}
	else
	{
		//多个节点
		SLTNode* pcur = *pphead;
		SLTNode* prev = *pphead;

		while (pcur != pos)
		{
			prev = pcur;
			pcur = pcur->next;
		}

		prev->next = pcur->next;

		free(pcur);
		pcur = NULL;
	}
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	//SLTPopFront(&plist);  //头删
	//SLTPopFront(&plist);

	SLTNode* pos = SLTFind(plist, 2);

	//SLTInsert(&plist, pos, 6); //在指定位置之前插入数据

	SLTErase(&plist, pos); //删除pos节点

	SLTPrint(plist);

}

int main()
{
	test();
	return 0;
}

 3.2.4.3在指定位置之后插入数据

         函数实现:

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyNode(x);

	newnode->next = pos->next;
	pos->next = newnode;
}

        测试代码:

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	//SLTPopFront(&plist);  //头删
	//SLTPopFront(&plist);

	SLTNode* pos = SLTFind(plist, 1);

	//SLTInsert(&plist, pos, 6); //在指定位置之前插入数据

	//SLTErase(&plist, pos); //删除pos节点

	SLTInsertAfter(pos, 7); //在指定位置之后插入数据

	SLTPrint(plist);

}

int main()
{
	test();
	return 0;
}

3.2.4.4删除pos之后的节点

        函数实现:

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);

	SLTNode* del = pos->next; //先用del存储pos->next指向的节点

	pos->next = pos->next->next; //将pos->next指向pos下一个节点的下一个节点
	free(del);
	del = NULL;
}

        测试代码: 

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	//SLTPopFront(&plist);  //头删
	//SLTPopFront(&plist);

	SLTNode* pos = SLTFind(plist, 2);

	//SLTInsert(&plist, pos, 6); //在指定位置之前插入数据

	//SLTErase(&plist, pos); //删除pos节点

	//SLTInsertAfter(pos, 7); //在指定位置之后插入数据

	SLTEraseAfter(pos);

	SLTPrint(plist);

}

int main()
{
	test();
	return 0;
}

3.2.5销毁链表

        函数实现: 

//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);

	SLTNode* pcur = *pphead;

	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}

	*pphead = NULL;
}

        测试代码: 

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	//SLTPopFront(&plist);  //头删
	//SLTPopFront(&plist);

	//SLTNode* pos = SLTFind(plist, 2);

	//SLTInsert(&plist, pos, 6); //在指定位置之前插入数据

	//SLTErase(&plist, pos); //删除pos节点

	//SLTInsertAfter(pos, 7); //在指定位置之后插入数据

	/*SLTEraseAfter(pos);*/

	SLTPrint(plist);

	SListDesTroy(&plist);

	SLTPrint(plist);
}

int main()
{
	test();
	return 0;
}

 3.3参考代码

//SList.h

#pragma once

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

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType val;
	struct SListNode* next;
}SLTNode;

//创建节点
SLTNode* BuyNode(SLTDataType x);

//打印链表
void SLTPrint(SLTNode* phead);

//头部插入删除/尾部插入删除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);
//SList.c

#include "SList.h"

SLTNode* BuyNode(SLTDataType x)
{
	SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newNode == NULL)
	{
		perror("malloc fail!\n");
		exit(1);
	}

	newNode->val = x;
	newNode->next = NULL;

	return newNode;
}

void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		printf("%d->", pcur->val);
		pcur = pcur->next;
	}
	printf("NULL\n");
}

//头部插入删除/尾部插入删除
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead); //下面要对pphead解引用,所以pphead不能为空
					//*pphead等同与指向头节点的指针,如果这个为空则
					//相当于为空链表,所以不用对*pphead进行断言
	//创建一个节点
	SLTNode* newnode = BuyNode(x);

	//空链表和非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//找尾
		SLTNode* ptail = *pphead;
		while (ptail->next)
		{
			ptail = ptail->next;
		}

		//在尾部进行插入
		ptail->next = newnode;
	}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);

	//创建一个节点
	SLTNode* newnode = BuyNode(x);

	//先将newnode->next指向之前的头节点,然后在将newnode作为新的头节点
	newnode->next = *pphead;
	*pphead = newnode;
}

void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	//链表不能为空链表
	assert(*pphead);

	//只有一个节点的情况和多个节点的情况
	if ((*pphead)->next == NULL) //只有一个节点
	{
		free(*pphead);
		*pphead = NULL;
	}
	else //多个节点
	{
		//找尾节点和尾节点前面的一个节点
		SLTNode* ptail = *pphead;
		SLTNode* prev = ptail; //prev表示尾节点的前面一个节点

		while (ptail->next)
		{
			prev = ptail; //将现在的尾节点给到prev
			ptail = ptail->next; //将尾节点的next变成新的尾节点
		}

		//删除尾节点
		free(ptail);
		prev->next = NULL;
	}
}

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);

	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
	del = NULL;
}

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* pcur = phead;

	while (pcur)
	{
		if (pcur->val == x)
		{
			//printf("找到了!\n");
			return pcur;
		}
		pcur = pcur->next;
	}
	//printf("没有找到!\n");
	return NULL;
}

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && *pphead);
	assert(pos);

	SLTNode* newnode = BuyNode(x);

	if (pos == *pphead)	//pos在第一个位置--头插入
	{
		SLTPushFront(pphead, x);
	}
	else //pos在中间和尾部
	{
		SLTNode* pcur = *pphead;
		SLTNode* prev = *pphead;
		while (pcur != pos)
		{
			prev = pcur;
			pcur = pcur->next;
		}

		newnode->next = pcur;
		prev->next = newnode;
	}
}

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);

	if (*pphead == pos)
	{
		//删除第一个节点--头删
		SLTPopFront(pphead);
	}
	else
	{
		//多个节点
		SLTNode* pcur = *pphead;
		SLTNode* prev = *pphead;

		while (pcur != pos)
		{
			prev = pcur;
			pcur = pcur->next;
		}

		prev->next = pcur->next;

		free(pcur);
		pcur = NULL;
	}
}

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyNode(x);

	newnode->next = pos->next;
	pos->next = newnode;
}

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next); //pos后面的节点必须存在

	SLTNode* del = pos->next; //先用del存储pos->next指向的节点

	pos->next = pos->next->next; //将pos->next指向pos下一个节点的下一个节点
	free(del);
	del = NULL;
}
//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);

	SLTNode* pcur = *pphead;

	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}

	*pphead = NULL;
}
//test.c

#include "SList.h"

void test()
{

	SLTNode* plist = NULL;

	SLTPushBack(&plist, 1); //尾插
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	//SLTPushFront(&plist, 5); //头插

	//SLTPopBack(&plist); //尾删
	//SLTPopBack(&plist);

	//SLTPopFront(&plist);  //头删
	//SLTPopFront(&plist);

	//SLTNode* pos = SLTFind(plist, 2);

	//SLTInsert(&plist, pos, 6); //在指定位置之前插入数据

	//SLTErase(&plist, pos); //删除pos节点

	//SLTInsertAfter(pos, 7); //在指定位置之后插入数据

	/*SLTEraseAfter(pos);*/

	SLTPrint(plist);

	SListDesTroy(&plist);

	SLTPrint(plist);
}

int main()
{
	test();
	return 0;
}

4.顺序表和单链表的优缺点分析

数据结构 单链表 C语言实现 单链表 单链表 顺序存储线性表 分配方式 分散存储 集中存储 时间性能 查找O(n) 插入删除O(1) 查找O(1) 插入删除O(n) 空间性能 无需分配空间,元素可以无限扩充 分配空间,元素个数有限 c语言代码实现(单链表) // // main.c // 线性表链式存储结构 // // Created by Kinble Wu on 2020/3/2. /... 阅读详情

相关推荐

C语言实现带头结点单链表

废话不多说,直接上代码: 先是.h文件,用来定义成员方法和成员变量: #pragma once #define TRUE 1 #define FALSE 0 //C语言里没有bool 故用宏定义实现 typedef int ElemType; typedef union Data { ElemType val; int length; }Data; typedef str...

weixin_43823473的博客 1064

单链表C语言实现及原理

单链表C语言实现及原理 一、简述 本文着重描述如何用C语言实现单链表的过程和原理,它包括了单链表所有的基础功能增、删、查、改。 关于单链表的定义就不在此赘述了。 本文是在参考了C语言单链表的基本操作总结(增删改查) 这篇文章之后,做出了一些优化,修复了部分bug,重新梳理了流程,使之更加简洁和容易理解,再次感谢原文作者。 代码如有任何错误或不妥,欢迎大家评论,给出宝贵建议。

Dennis_China的博客 6811

手把手教你解决COLMAP编译中的Ceres CUDA支持问题(附详细配置步骤)

本文详细解析了COLMAP编译中Ceres CUDA支持问题的完整解决方案,包括环境准备、Ceres Solver的CUDA编译配置、COLMAP的CUDA集成配置等关键步骤。通过优化CMake参数和解决常见错误,帮助技术人员充分利用GPU加速优势,提升三维重建效率。

vodka的博客 861

单链表及C语言实现

本博文介绍单链表,及其C语言的实现 单链表 单链表操作 插入 头节点插入 尾节点插入 指定位置插入 删除 头节点删除 尾节点删除 指定为位置删除 遍历 查找 单链表所有相关操作的代码实现见Github ...

Jeaten 5116

基于BS21的星闪模块设计电路SLE/BLE

基于BS21的星闪模块设计电路SLE/BLE HI2821

2503_91889531的博客 2739

手机拍照也能玩高光谱?教你用TensorFlow Lite在Android上实现实时RGB转高光谱

本文介绍了如何利用TensorFlow Lite在Android设备上实现实时RGB到高光谱的图像重构技术。通过深度学习模型优化和移动端部署策略,使智能手机具备专业级光谱分析能力,适用于农业检测、化妆品分析等多个领域。

weixin_29091105的博客 247

C语言实现单链表

C语言实现单链表

sgz0527的博客 2273

cilium native-routing模式流程分析

本文分析cilium native routing模式下的报文路径和涉及到的ebpf源码分析。实验环境在vxlan模式下修改参数后而来。native routing和vxlan模式的区别主要是跨节点通信时,vxlan模式需要封装,native routing模式需要根据目的ip查找路由表转发到其他节点。

fengcai_ke的博客 989

数据结构——单链表(C语言实现)

单链表的基本操作有 初始化,头插,尾插,按位置插,头删,尾删,按位置删,查找,按值删,获取有效值个数,判空,清空,销毁,打印 - 单链表是一种链式存取的数据结构,链表中的数据是以结点来表示的,每个结点的构成:==元素(数据元素的映象)== + ==指针(指示后继元素存储位置)==,元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示的线性表称作线性链表(单链表),单链表是链式存取的结构。

weixin_57154303的博客 4582

杰理AC695N系列芯片红外遥控按键使用教程

本文介绍了杰理AC695N芯片红外按键功能的配置和使用方法。主要内容包括:硬件连接说明(红外接收头接线至GPIO口)、软件配置(使能红外功能并设置接收引脚)、按键映射表修改(原始键值到逻辑按键的转换)以及按键扫描参数调整(消抖、长按时间等)。重点展示了三级映射机制,指导如何根据实际遥控器键值修改映射关系,实现不同模式下(蓝牙/音乐/FM)的自定义按键功能。最后提供了调试方法,可通过串口打印查看遥控器原始键值。

qq_42014563的博客 1463

基于逆向工程的中国裁判文书网爬虫技术深度解析:从反爬破解到合规抓取

最近承接了一个法律大数据分析的项目,需要获取某类合同纠纷的裁判文书数据,用于分析不同地区的判决规律、法官的裁判倾向以及法条适用情况。原本以为用常规的Python爬虫就能搞定,结果刚对着中国裁判文书网发了几个请求,就遭遇了“滑铁卢”:要么请求直接返回403 Forbidden,要么触发滑块验证码,甚至连IP都被临时封禁了。普通的requests+BeautifulSoup组合在裁判文书网面前完全失效,这也让我意识到,想要获取这里的数据,必须先通过逆向工程拆解网站的请求逻辑和反爬机制。经过一周的摸索,从抓包分析

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 3172

单链表—C语言实现数据结构

本文具体讲解单链表的结构,内容较为丰富,干货多多

2201_76062618的博客 5105

第三篇:NVIDIA cuOpt Python API 详解:LP、QP、MILP 建模与求解,附核心术语名词解释

NVIDIA cuOpt是一款GPU加速的优化求解库,支持LP、QP、MILP和路径优化问题。本文详细介绍了其Python API使用方法,包括核心类Problem的变量定义、约束添加、目标设置和求解配置,并提供了术语解释。cuOpt通过GPU并行计算大幅提升大规模优化问题的求解效率,支持多种求解算法和参数配置,适用于需要高性能计算的优化场景。安装方式包含pip和Docker两种,验证安装后即可快速开始建模求解。

算法工程师 236

单链表的C语言实现

今天学习了单链表,并写出了其的C语言实现,验证了一下感觉基本正确。但是代码的健壮性不够,对于有的不合法的输入,并没有显示输出错误。 代码可以直接贴在编译器上编译执行,我已经写过主函数了。 如有错误,欢迎指正。 #include #include typedef struct LNode { int data; LNode *next; }LNode,

Enjoy IT! 924

亚马逊跨境电商选品数据分析:Python爬虫实战指南

本文将带领大家构建一套完整的亚马逊选品数据采集与分析系统,使用最新的Python技术栈,从零开始爬取亚马逊商品数据,并进行深度分析。

2201_76125261的博客 299

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C语言单链表实现

一:NOTE 今天分享一下单链表(有空头)的一些操作!主要呢就是增、删、打印! 二:预备知识 单链表可以比喻成一趟火车,有空头的单链表就像是一个火车头拉着一节有一节的车厢。一个车厢中有数据域和指针域,指针域用来连接,每节车厢肯定要有东西连着,不然就没有方向了。如图 所以连接的时候只要将指针域指向下一个节点就是连接上了,然后删除呢 给个图应该很清楚了 三:明确步骤 写程序前,首先捋清楚程序有哪些...

qq_43590728的博客 459

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

循环单链表及C语言实现

本博文介绍循环单链表及其C语言的实现 目录循环单链表循环单链表的操作插入头节点插入尾节点插入删除遍历查找循环单链表的C语言实现 循环单链表 循环单链表的操作 插入 头节点插入 尾节点插入 删除 遍历 查找 循环单链表的C语言实现 ...

Jeaten 2270

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【C语言】实现单链表

所以创建一个del指针,暂时保存链表的原头(也是将要释放的节点),当链表的头指针后移找到新头后,再通过del释放原头。包括打印单链表,头插与头删,尾插与尾删,删除指定位置的节点,删除指定位置之后的节点,指定位置之前插入节点,指定位置之后插入节点,销毁链表等十个功能。首先传递的指针不为空,链表也不为空(如果pos不为空,所以链表一定不为空,【因为链表为空是pos为空的充分条件】两者是逆否命题),通过assert断言来判断;指定位置之前插入节点 与 指定位置之前删除节点类似,都需要创建prev指针,遍历链表;

石墨博客 1760

C语言实现 -- 单链表

C语言实现 -- 单链表

m0_64364831的博客 1090

单链表的实现(C语言)

创建一个指针 ptail 让它指向链表的头节点,如果链表不为空,就找到链表的尾部,只需要 ptail 的下一个节点为空,那么此时ptail就是链表的尾部,然后让 ptail 的下一个节点指向新增节点newnode就完成了尾插操作。然后创建一个指向头节点的指针,遍历链表,通过while循环这个指针的下一个节点不指向pos,那么循环结束的时候它就是pos的前一个节点。从头开始销毁链表是最好的,创建一个指针指向头节点的下一个节点,然后销毁头节点,最后让头节点的下一个指针成为新的头节点,遍历销毁链表。

2303_80078385的博客 1391

数据结构——单链表的实现(C语言版)

数据结构——单链表的实现(C语言版)

qq_64034271的博客 1704

单链表 C语言实现

实现单链表的各种增删改查 以及排序,逆置,显示,清空等功能

Chengzi_comm的专栏 1018

c语言链表查找的代码与题目,链表的C语言实现之单链表的查找运算_c语言

建立了一个单链表之后,如果要进行一些如插入、删除等操作该怎么办?所以还须掌握一些单链表的基本算法,来实现这些操作。单链表的基本运算包括:查找、插入和删除。下面我们就一一介绍这三种基本运算的算法,并结合我们建立单链表的例子写出相应的程序。1、查找对单链表进行查找的思路为:对单链表的结点依次扫描,检测其数据域是否是我们所要查好的值,若是返回该结点的指针,否则返回NULL。{post_permalink...

weixin_29710403的博客 915

C语言--单链表的所有操作实现

单链表的所有操作实现 // 动态申请一个节点 SListNode* BuySListNode(SLTDateType x) //链表初始化 void SListInit(Head* plist) // 单链表打印 void SListPrint(Head* plist) // 单链表尾插 void SListPushBack(Head* pplist, SLTDateType x) // ...

loreal8的博客 354
上一篇: 用C语言实现顺序表
下一篇: C语言实现双向链表
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值