链表C语言实现

一.什么是链表?

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


二.链表的种类

按照带头结点和不带头结点,
单向还是双向,
循环还是非循环,可以分为八种


三.链表的实现

1.不带头非循环单链表

每个节点有自己的数据,并且有一个指针指向链表的下一个节点,
单链表的最后一个节点指向NULL

1)数据结构的定义
//不带头单向链表

typedef int DataType;	//数据元素类型

//链表的节点
typedef struct ListNode
{
	DataType val;		//存储的数据
	struct ListNode* next;	//下一个节点的指针
}ListNode;

//链表
typedef struct List
{
	//第一个节点的指针
	ListNode* head;
}List;
2)核心操作的实现

初始化链表

//初始化链表
void ListInit(List* lst)
{
	if (lst == NULL)
		return;

	lst->head = NULL;
}

创建新节点

//创建新节点
ListNode* createNode(DataType val)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	node->val = val;
	node->next = NULL;
	return node;
}

销毁单链表

//销毁单链表
void DestroyList(List* lst)
{
	if (lst == NULL)
		return;

	struct ListNode* node = lst->head;
	while (node)
	{
		struct ListNode* nextNode = node->next;
		free(node);
		node = nextNode;
	}
}

插入删除、尾插尾删、头插头删实现见源码

3)源码

LinkList.h

#pragma once 

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

//不带头单向链表

typedef int DataType;

typedef struct ListNode
{
	DataType val;
	struct ListNode* next;
}ListNode;

typedef struct List
{
	//第一个节点的指针
	ListNode* head;
}List;

//初始化链表
void ListInit(List* lst);

//创建新节点
ListNode* createNode(DataType val);

//销毁单链表
void DestroyList(List* lst);

//尾插
bool ListPushBack(List* lst, DataType val);

//头插
bool ListPushFront(List* lst, DataType val);

//尾删
bool ListPopBack(List* lst);

//头删
bool ListPopFront(List* lst);

//插入:node的后面进行插入
bool ListInsert(List* lst, ListNode* node, DataType val);

//删除
bool ListErase(List* lst, ListNode* target);

//查找val对应的节点
ListNode* findNode(List* lst, DataType val);

//获取元素个数
int getSize(List* lst);

//判空
bool isEmpty(List* lst);

//获取链表头部元素
ListNode* getListFront(List* lst);

//获取链表尾部元素
ListNode* getListBack(List* lst);

//打印单链表
void PrintList(List* lst);

LinkList.c

#include "LinkList.h"

//初始化链表
void ListInit(List* lst)
{
	if (lst == NULL)
		return;

	lst->head = NULL;
}

//创建新节点
ListNode* createNode(DataType val)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	node->val = val;
	node->next = NULL;
	return node;
}

//销毁单链表
void DestroyList(List* lst)
{
	if (lst == NULL)
		return;

	struct ListNode* node = lst->head;
	while (node)
	{
		struct ListNode* nextNode = node->next;
		free(node);
		node = nextNode;
	}
}

//尾插
bool ListPushBack(List* lst, DataType val)
{
	if (lst == NULL)
		return false;

	struct ListNode* newNode = createNode(val);

	if (lst->head == NULL)
		lst->head = newNode;
	else
	{
		//找到尾节点
		struct ListNode* tail = lst->head;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		//将新节点链接到尾部
		tail->next = newNode;
	}
	return true;
}

//头插
bool ListPushFront(List* lst, DataType val)
{
	if (lst == NULL)
		return false;

	struct ListNode* newNode = createNode(val);

	if (lst->head == NULL)
		lst->head = newNode;
	else
	{
		//重新链接
		newNode->next = lst->head;
		//更新头节点
		lst->head = newNode;
	}

	return true;
}

//尾删
bool ListPopBack(List* lst)
{
	if (lst == NULL || lst->head == NULL)
		return false;

	struct ListNode* prev = NULL;
	struct ListNode* node = lst->head;

	//找到尾节点的前一个节点
	while (node->next)
	{
		prev = node;
		node = node->next;
	}

	//释放节点
	free(node);

	//更新指向
	//删除的是头节点
	if (prev == NULL)
		lst->head = NULL;
	else
		prev->next = NULL;

	return true;
}

//头删
bool ListPopFront(List* lst)
{
	if (lst == NULL || lst->head == NULL)
		return false;

	//释放空间+更新头节点
	//头节点后面的元素为空时,空节点就是头节点
	struct ListNode* newHead = lst->head->next;
	free(lst->head);
	lst->head = newHead;

	return true;
}

//插入:node的后面进行插入
bool ListInsert(List* lst, ListNode* node, DataType val)
{
	if (lst == NULL)
		return false;

	//链表为空
	if (lst->head == NULL && node == NULL)
	{
		lst->head = createNode(val);
		return true;
	}
	
	//空节点后面插入视为头插
	if(node == NULL){
		struct ListNode* newNode = createNode(val);
		newNode->next = lst->head;
		lst->head = newNode;
		return true;
	}
	
	//查找node节点是否存在
	struct ListNode* p = lst->head;
	bool flag = false;	//表示是否找到了node节点
	while (p)
	{
		if (p == node)
		{
			flag = true;
			break;
		}
		node = node->next;
	}
	
	//节点不存在
	if (flag == false)
		return false;

	//创建新节点
	struct ListNode* newNode = createNode(val);
	struct ListNode* nextNode = node->next;
	node->next = newNode;
	newNode->next = nextNode;

	return true;
}

//删除target节点
bool ListErase(List* lst, ListNode* target)
{
	if (lst == NULL || lst->head == NULL || target == NULL)
		return false;

	//删除的是头节点
	if (lst->head == target)
	{
		lst->head = lst->head->next;
		free(target);
		return true;
	}

	struct ListNode* node = lst->head;
	struct ListNode* prev = NULL;	//被删除节点的前一个节点

	//查找要删除的节点
	while (node)
	{
		if (node->next == target)
		{
			prev = node;
			break;
		}
		node = node->next;
	}

	//没找到要删除的节点
	if (prev == NULL)
		return false;

	prev->next = target->next;
	free(target);
	return true;
}


//查找val对应的节点
ListNode* findNode(List* lst, DataType val)
{
	if (lst == NULL || lst->head == NULL)
		return NULL;

	struct ListNode* node = lst->head;
	while (node)
	{
		if (node->val == val)
			return node;
		node = node->next;
	}
	return NULL;
}

//获取元素个数
int getSize(List* lst)
{
	if (lst == NULL || lst->head == NULL)
		return 0;

	int sz = 0;
	struct ListNode* node = lst->head;
	while (node)
	{
		sz++;
		node = node->next;
	}

	return sz;
}

//判空
bool isEmpty(List* lst)
{
	return lst == NULL || lst->head == NULL;
}

//获取链表头部元素
ListNode* getListFront(List* lst)
{
	if (lst == NULL)
		return NULL;

	return lst->head;
}

//获取链表尾部元素
ListNode* getListBack(List* lst)
{
	if (lst == NULL)
		return NULL;

	struct ListNode* node = lst->head;
	while (node->next)
	{
		node = node->next;
	}
	return node;
}

//打印单链表
void PrintList(List* lst)
{
	if (lst == NULL || lst->head == NULL)
		return;

	struct ListNode* node = lst->head;
	while (node)
	{
		printf("%d", node->val);
		if (node->next != NULL)
			printf("-->");
		node = node->next;
	}
	printf("\n");
}

2.带头循环双向链表

链表有一个头节点,每个节点有自己的数据,有两个指针(前驱指针和后继指针),分别指向前一个节点和后一个节点,最后一个节点的后继指针指向头节点,头节点的前驱指针指向最后一个节点

1)数据结构的定义
typedef int DataType;	//链表节点元素类型

//链表节点
struct ListNode
{
	DataType val;			//存储的数据
	struct ListNode* prev;	//前驱节点
	struct ListNode* next;	//后继节点
};
typedef struct ListNode ListNode;

//带头结点的双向链表
typedef struct List
{
	ListNode* head;
}List;
2)核心操作的实现

新建一个链表节点

//新建一个链表节点
ListNode* createListNode(DataType val)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	node->val = val;
	node->prev = NULL;
	node->next = NULL;
	return node;
}

链表的初始化

//链表初始化
void ListInit(List* lst)
{
	if (lst == NULL)
		return;

	lst->head = createListNode(INT_MIN);
	//让头节点指向自身
	lst->head->prev = lst->head->next = lst->head;
}

链表的销毁

//链表的销毁
void ListDestroy(List* lst)
{
	if (lst == NULL)
		return;

	struct ListNode* node = lst->head->next;
	while (node != lst->head)
	{
		ListNode* nextNode = node->next;
		free(node);
		node = nextNode;
	}

	//释放头节点
	free(lst->head);	
}

插入节点

//节点之后插入新节点
bool insertAfterNode(List* lst, ListNode* node, DataType val) {
	if (lst == NULL) {
		return false;
	}
	
	//头节点之后插入
	if (node == lst->head) {
		ListNode* nextNode = node->next;
		ListNode* newNode = createNode(val);
		newNode->prev = lst->head;
		newNode->next = nextNode;
		nextNode->prev = newNode;
		lst->head->next = newNode;
		return true;
	}

	//查找节点是否存在于链表中
	ListNode* curNode = lst->head->next;
	bool isExist = false;		//是否存在标志位
	while (curNode != lst->head) {
		if (curNode == node) {
			isExist = true;
			break;
		}
		curNode = curNode->next;
	}

	//节点在链表中,在节点后面插入新节点
	if (isExist) {
		ListNode* nextNode = node->next;
		ListNode* newNode = createNode(val);
		node->next = newNode;
		newNode->prev = node->prev;
		newNode->next = nextNode;
		nextNode->prev = newNode;
		return true;
	}
	else {
		//目标节点不在链表中,返回
		return false;
	}
}

删除节点

//删除节点
bool eraseNode(List* lst, ListNode* node) {
	if (lst == NULL) {
		return false;
	}

	//查找节点是否在链表中
	bool isExist = false;	//节点是否在链表中标志位
	ListNode* curNode = lst->head;
	while (curNode != curNode->prev) {
		if (curNode == node) {
			curNode->prev->next = curNode->next;
			curNode->next->prev = curNode->prev;
			free(curNode);
			isExist = true;
			break;
		}
		else {
			curNode = curNode->next;
		}
	}
	if (!isExist) {
		return false;
	}
	return true;
}

头插、头删、尾插、尾删见下面的源码

3)源码

LinkList.h

#pragma once

//带头双向循环链表
//vs2013编译器无法识别typedef是最困扰我的问题

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>		//INT_MIN
		
typedef int DataType;	//链表节点元素类型

//链表节点
struct ListNode
{
	DataType val;			//存储的数据
	struct ListNode* prev;	//前驱节点
	struct ListNode* next;	//后继节点
};
typedef struct ListNode ListNode;

//带头结点的双向链表
typedef struct List
{
	ListNode* head;
}List;

//新建一个链表节点
ListNode* createListNode(DataType val);

//销毁链表节点
void DestroyNode(ListNode* node);

//链表初始化
void ListInit(List* lst);

//链表的销毁
void ListDestroy(List* lst);

//节点之后插入新节点
bool insertAfterNode(List* lst, ListNode* node, DataType val);

//删除节点
bool eraseNode(List* lst, ListNode* node);

//头插
bool pushFront(List* lst, DataType val);

//尾插
bool pushBack(List* lst, DataType val);

//头删
bool popFront(List* lst);

//尾删
bool popBack(List* lst);

//判空
bool IsEmpty(List* lst);

//获取链表节点个数
int getSize(List* lst);

//从头到尾打印链表元素
void PrintList(List* lst);

//根据值查找链表节点
ListNode* findNode(List* lst, DataType val);

LinkList.c

#include "LinkList.h"

//新建一个链表节点
ListNode* createListNode(DataType val)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	node->val = val;
	node->prev = NULL;
	node->next = NULL;
	return node;
}

//销毁链表节点
void DestroyNode(ListNode* node)
{
	if (node == NULL)
		return;

	free(node);
	node->prev = node->next = NULL;
}

//链表初始化
void ListInit(List* lst)
{
	if (lst == NULL)
		return;

	lst->head = createListNode(INT_MIN);
	//让头节点指向自身
	lst->head->prev = lst->head->next = lst->head;
}

//链表的销毁
void ListDestroy(List* lst)
{
	if (lst == NULL)
		return;

	struct ListNode* node = lst->head->next;
	while (node != lst->head)
	{
		ListNode* nextNode = node->next;
		free(node);
		node = nextNode;
	}

	//释放头节点
	free(lst->head);	
}

//节点之后插入新节点
bool insertAfterNode(List* lst, ListNode* node, DataType val) {
	if (lst == NULL) {
		return false;
	}
	
	//头节点之后插入
	if (node == lst->head) {
		ListNode* nextNode = node->next;
		ListNode* newNode = createNode(val);
		newNode->prev= lst->head;
		newNode->next = nextNode;
		nextNode->prev= newNode;
		lst->head->next = newNode;
		return true;
	}

	//查找节点是否存在于链表中
	ListNode* curNode = lst->head->next;
	bool isExist = false;		//是否存在标志位
	while (curNode != lst->head) {
		if (curNode == node) {
			isExist = true;
			break;
		}
		curNode = curNode->next;
	}

	//节点在链表中,在节点后面插入新节点
	if (isExist) {
		ListNode* nextNode = node->next;
		ListNode* newNode = createNode(val);
		node->next = newNode;
		newNode->prev= node->prev;
		newNode->next = nextNode;
		nextNode->prev= newNode;
		return true;
	}
	else {
		//目标节点不在链表中,返回
		return false;
	}
}

//删除节点
bool eraseNode(List* lst, ListNode* node) {
	if (lst == NULL) {
		return false;
	}

	//查找节点是否在链表中
	bool isExist = false;	//节点是否在链表中标志位
	ListNode* curNode = lst->head;
	while (curNode != curNode->prev) {
		if (curNode == node) {
			curNode->prev->next = curNode->next;
			curNode->next->prev = curNode->front;
			free(curNode);
			isExist = true;
			break;
		}
		else {
			curNode = curNode->next;
		}
	}
	if (!isExist) {
		return false;
	}
	return true;
}

//头插
bool pushFront(List* lst, DataType val)
{
	if (lst == NULL)
		return false;

	struct ListNode* newNode = createListNode(val);
	struct ListNode* prev = lst->head;
	struct ListNode* next = lst->head->next;

	//更新连接
	newNode->prev = prev;
	newNode->next = next;
	prev->next = newNode;
	next->prev = newNode;

	return true;
}

//尾插
bool pushBack(List* lst, DataType val)
{
	if (lst == NULL)
		return false;

	struct ListNode* newNode = createListNode(val);
	struct ListNode* tail = lst->head->prev;	//尾节点

	//插入尾节点的下一个位置
	newNode->prev = tail;
	newNode->next = lst->head;
	lst->head->prev = newNode;
	tail->next = newNode;

	return true;
}

//头删
bool popFront(List* lst)
{
	//头节点不能删
	if (lst->head->prev == lst->head && lst->head->next == lst->head)
		return false;

	struct ListNode* curNode = lst->head->next;	//要删除的节点
	struct ListNode* nextNode = curNode->next;	//要删除节点的下一个节点

	free(curNode);
	lst->head->next = nextNode;
	nextNode->prev = lst->head;

	return true;
}

//尾删
bool popBack(List* lst)
{
	//头节点不能删
	if (lst->head->prev == lst->head && lst->head->next == lst->head)
		return false;

	struct ListNode* curNode = lst->head->prev;	//要删除的节点:尾节点
	struct ListNode* prevNode = curNode->prev;	//要删除节点的前一个节点

	free(curNode);
	prevNode->next = lst->head;
	lst->head->prev = prevNode;

	return true;
}

//判空
bool IsEmpty(List* lst)
{
	return lst->head == lst->head->prev && lst->head == lst->head->next;
}

//获取链表节点个数
int getSize(List* lst)
{
	if (lst == NULL || (lst->head->next == lst->head && lst->head->prev == lst->head))
		return 0;
	int sz = 0;
	struct ListNode* p = lst->head->next;

	while (p != lst->head)
	{
		++sz;
		p = p->next;
	}
	return sz;
}

//从头到尾打印链表元素
void PrintList(List* lst)
{
	if (lst == NULL)
		return;

	struct ListNode* p = lst->head->next;

	while (p != lst->head)
	{
		printf("%d ", p->val);
		p = p->next;
	}
	printf("\n");
}

//根据值查找链表节点
ListNode* findNode(List* lst, DataType val)
{
	if (lst == NULL)
		return NULL;

	struct ListNode* p = lst->head->next;
	while (p != lst->head)
	{
		if (p->val == val)
		{
			return p;
		}
		p = p->next;
	}
	return NULL;
}

四.链表和顺序表的区别

顺序表的空间是连续的,链表的空间是非连续的;
顺序表支持随机访问,链表不支持随机访问;
顺序表在满了的时候需要增容,链表不需要增容,链表每次插入一个新节点就为这个节点分配空间;
顺序表除了尾部插入和删除的时间复杂度为O(1)外,其它位置插入和删除的时间复杂度都为O(N),链表任何位置插入和删除的时间复杂度都是O(1);

五.链表相关的编程题

对链表进行插入排序

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值