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

21 篇文章 11 订阅
12 篇文章 0 订阅

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

本次介绍三种单链表:普通单链表、循环链表和双向链表,后面的博客会继续介绍后两种链表


首先介绍单链表的特点:

1.链表是由一个个内存地址不连续的节点组成

2.每个节点最多只有一个前驱,一个后记(第一个节点只有后继没有前驱,最后一个节点只有前驱没有后继)

3.链表不支持随机存取(意思就是不能通过下标来进行找某个节点,只能从头到尾进行遍历)

4.链表的查找只能从头到尾对链表进行遍历,时间复杂度为O(n);而顺序表查找元素只要给一个下标即可,时间复杂度为O(1)

5.删除链表的某个节点时只需改变节点的指针,不需要移动大量元素


然后从三个方面来介绍三种链表的通用操作:

1.链表的初始化

2.申请一个链表节点

3.链表的头插法

4.链表的尾插法

5.获取链表长度

6.删除链表节点

7.查找指定值的节点

8.销毁链表(释放链表所有节点的内存空间)

9.输出单链表(输出单链表所有节点的数据域)


说明:以下单链表的实现,是数据域以整型为例,而且带有头结点。


一、普通单链表

1.单链表的结构

typedef struct _Node

{

int data;//数据域

struct _Node* next;//指针域

}Node, *List;


2.链表的操作

(1)链表的初始化(带头结点)

这里的初始化只要是指初始化头结点的指针域

void InitList(List plist)
{
	if (NULL == plist)
		return;
	plist->next = NULL;
}

(2).申请一个链表节点

从堆中申请一个节点,注意这里是从堆中申请的内存,只能通过free(p)显式释放内存。即使是局部变量,该内存也不会随着函数调用完成而释放该内存。

static Node* BuyNode(int val)
{
	Node* pTmp = (Node*)malloc(sizeof(Node));
	pTmp->next = NULL;
	return pTmp;
}


(3).链表头插法

这里的链表是带有头结点的,所以每次新插入的节点应插入头结点后面。

void InsertHead(List plist, int val)
{
	Node *pTmp = BuyNode(val);	//申请一个节点,数据域为val
	pTmp->next = plist->next;	
	plist->next = pTmp;
}


(4).链表尾接法

每次将新插入的节点插入到最后一个节点后面,所以采用尾接法插入节点时首先要找到尾节点

void InsertTail(List plist, int val)
{
	Node *pTmp = BuyNode(val);
	Node *pCur;
	for (pCur = plist; NULL != pCur; pCur = pCur->next)	//查找尾节点
	{
		;		//空语句
	}
	pCur->next = pTmp;	//将新节点插入到尾节点之后
}


(5).获取链表长度

对链表进行遍历,每遍历一个节点,计数器加一。

int GetListLen(List plist)
{
	Node *pTmp = plist->next;
	int iCount = 0;
	while (NULL != pTmp)
	{
		++iCount;
		pTmp = pTmp->next;
	}
	return iCount;
}


(6).删除链表节点

删除指定值的链表节点时,需要遍历该链表,找到对应节点后想要删除该节点必须要知道该节点的前驱节点,这样才能正确删除该节点。

bool Delete(List plist, int val)
{
	Node* pPre = plist;		//指向前驱节点
	Node* pCur = plist->next;	//指向当前比较的节点
	while (NULL != pCur)	//当链表没找完就继续找
	{
		if (pCur->data != val)	//链表没找到就更新当前节点和它的前驱节点
		{
			pPre = pCur;		//更新前驱节点为当前节点
			pCur = pCur->next;	//更新当前节点为下一个节点
		}
		else
		{
			pPre->next = pCur->next;	
			free(pCur);		//释放待删节点的内存
			return true;		//找到该节点返回true
		}
	}
	return false;
}


(7).查找指定值的节点

查找指定值的节点也需要从头到尾遍历链表,若找到则返回该节点,没找到则返回NULL。

Node* Search(List plist, int val)
{
	Node *pCur = plist->next;
	while (NULL != pCur)
	{
		if (pCur->data == val)
		{
			return pCur;
		}
		pCur = pCur->next;
	}
	return NULL;
}


(8).销毁链表

销毁链表就是释放链表中所有节点的内存。

void Destroy(List plist)
{
	Node* pCur = plist->next;	//注意销毁链表后头结点的内存空间还是存在的,即空链表就是只有一个头结点的单链表
	while (NULL != pCur)
	{
		plist = pCur->next;
		free(pCur);
		pCur = plist->next;
	}
}


(9).输出单链表

输出单链表的操作也比较简单,从头到尾遍历单链表,每遍历一个节点就输出该节点的指针域

void Show(List plist)
{
	Node* pCur = plist->next;
	while (NULL != pCur)
	{
		printf("%5d", pCur->data);
		pCur = pCur->next;
	}
	printf("\n");
}


最后附上完整代码和运行结果:

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

typedef struct _Node
{
	int data;
	struct _Node* next;
}Node, *List;

void InitList(List plist);
void InsertHead(List plist, int val);
void InsertTail(List plist, int val);
bool Delete(List plist, int val);
Node* Search(List plist, int val);
int GetListLen(List plist);
void Destroy(List plist);
static Node* BuyNode(int val);
void Show(List plist);



//Link.c
#include "test.h"


int main()
{
	Node head;
	InitList(&head);
	for (int i = 0; i < 13; ++i)
	{
		InsertTail(&head, i);	//尾插法
	}
	ShowList(&head);
	printf("链表长度:%d\n", GetListLen(&head));
	
	for (int i = 0; i < 12; ++i)
	{
		InsertHead(&head, i);	//头插法
	}
	ShowList(&head);
	printf("链表长度:%d\n", GetListLen(&head));
	printf("search 12:\n");
	Node *p = Search(&head, 12);	//查找节点
	if (p != NULL)
	{
		printf("%d\n", p->data);
	}
	else
	{
		printf("Not Found\n");
	}
	
	printf("删除节点12:\n");	//删除节点
	if (Delete(&head, 12))
	{
		ShowList(&head);
	}
	else
	{
		printf("链表中无此节点\n");
	}
		
	Destroy(&head);		//销毁链表
	return 0;
}


void InitList(List plist)
{
	if (NULL == plist)
		return;
	plist->next = NULL;
}
void InsertHead(List plist, int val)
{
	Node *pTmp = BuyNode(val);
	pTmp->next = plist->next;
	plist->next = pTmp;
}
void InsertTail(List plist, int val)
{
	Node *pTmp = BuyNode(val);
	Node *pCur;
	for (pCur = plist; NULL != pCur->next; pCur = pCur->next)
	{
		;		//空语句
	}
	pCur->next = pTmp;
}
bool Delete(List plist, int val)
{
	Node* pPre = plist;
	Node* pCur = plist->next;
	while (NULL != pCur)
	{
		if (pCur->data != val)
		{
			pPre = pCur;
			pCur = pCur->next;
		}
		else
		{
			pPre->next = pCur->next;
			free(pCur);
			return true;
		}
	}
	return false;
}
Node* Search(List plist, int val)
{
	Node *pCur = plist->next;
	while (NULL != pCur)
	{
		if (pCur->data == val)
		{
			return pCur;
		}
		pCur = pCur->next;
	}
	return NULL;
}
int GetListLen(List plist)
{
	Node *pTmp = plist->next;
	int iCount = 0;
	while (NULL != pTmp)
	{
		++iCount;
		pTmp = pTmp->next;
	}
	return iCount;
}
void Destroy(List plist)
{
	Node* pCur = plist->next;	//注意销毁链表后头结点的内存空间还是存在的,即空链表就是只有一个头结点的单链表
	while (NULL != pCur)
	{
		plist = pCur->next;
		free(pCur);
		pCur = plist->next;
	}
}
static Node* BuyNode(int val)
{
	Node* pTmp = (Node*)malloc(sizeof(Node));
	pTmp->next = NULL;
	pTmp->data = val;
	return pTmp;
}
void ShowList(List plist)
{
	Node* pCur = plist->next;
	while (NULL != pCur)
	{
		printf("%5d", pCur->data);
		pCur = pCur->next;
	}
	printf("\n");
}


运行结果:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值