链式结构-单链表

本文介绍了如何使用C语言实现单链表的数据结构,包括初始化链表、动态申请节点、插入节点(头插法、尾插法)、删除节点(头删法、尾删法、按值删除)、查找节点以及链表的清理和销毁等操作。这些操作涉及到内存管理,如malloc和free函数的使用,以及指针的处理技巧。
摘要由CSDN通过智能技术生成

概述:

将非连续地址空间里的数据以一种特殊的方式(指针) 串在一起。

 带头结点的单链表结构:

每个节点有两个域,数据域存储数据,指针域存储下一个节点的地址,无后续节点,则指针域为NULL(空指针)。

如图:

 结构设计:

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

typedef int ElemType;
typedef struct ListNode
{
 ElemType data;                   //存储数据
 struct ListNode* next;           //指针域
}ListNode,*PListNode;             //节点类型
typedef struct
{
 ListNode* head; // 头节点
 int cursize;    // 数据个数;
}LinkList;                       //链表头节点

 1.动态申请节点函数:

利用malloc函数申请内存空间,进行数据写入

ListNode* Buynode(ElemType val,ListNode *narg)   //数据和下一节点地址
{
 ListNode* s = (ListNode*)malloc(sizeof(ListNode));
 if (nullptr == s)
 {
  exit(EXIT_FAILURE);    //内存申请失败,终止程序
 }
 s->data = val;          //写入数据
 s->next = narg;         //next指针指向下一节点
 return s;
}

2.初始化函数(创建一个空链表)

void InitList(LinkList* plist)
{
 assert(plist != nullptr);       //安全性检测
 plist->cursize = 0;             //数据个数
 plist->head = Buynode(0, nullptr);
}

3.释放节点函数

void Freenode(ListNode* p)
{
 free(p);    //函数内部有空指针检测,无需assert检测
 p=nullptr;  //置空
}

4.在指定节点后插入节点 函数

需要先将插入节点的指针指向后续节点,然后将上一个节点的指针指向插入节点便可。

(先1后2,顺序不可改变,否则将无法找到后续节点) 

void InsertNext(LinkList* plist, ListNode* ptr, ElemType val)
{
 assert(plist != nullptr && ptr != nullptr);
 ptr->next = Buynode(val, ptr->next);
 plist->cursize += 1;
}

尾插法:

 
void InsertTail(LinkList* plist, ElemType val)
{
 assert(plist != nullptr);
 ListNode* p = plist->head;
 while (p->next != nullptr)   //找到最后一个节点
 {
  p = p->next;
 }
 InsertNext(plist, p, val);  //代码复用
}
 

头插法:

 
void InsertHead(LinkList* plist, ElemType val)
{
  assert(plist != nullptr);           
  InsertNext(plist,plist->head,val);  //代码复用
}

5.删除指定节点的后一节点

用指针保存待删节点的地址,将指定节点的指针指向待删节点的后一节点,释放待删节点的内存。

void Erasenext(LinkList* plist,ListNode* ptr)
{
	assert(plist != nullptr && ptr != nullptr);
	if(ptr->next == nullptr) return ;   
	ListNode* p = ptr->next;
	ptr->next = p->next;
	Freenode(p);
	plist->cursize--;
}

头删法:

void EraseFrist(LinkList* plist)
{
	assert(plist != nullptr);
	Erasenext(plist,plist->head);
}

尾删法:

void EraseLast(LinkList* plist)
{
	assert(plist != nullptr);
	if(plist->cursize == 0) return ;
	ListNode* ptr,*str;
	ptr=plist->head->next;
	str=plist->head;
	while(ptr != nullptr && ptr->next != nullptr)
	{
		str= ptr;
		ptr = ptr->next;
	}
	Erasenext(plist,str);
}

6.查找指定元素的前驱节点:

原理:双指针遍历法

ListNode* Findvalueprev(LinkList* plist,ElemType val)
{
	assert(plist != nullptr);
	ListNode* ptr=plist->head->next;
	ListNode* ptrprev=plist->head;
	while(ptr->data != val && ptr != nullptr)
	{
		ptrprev=ptr;
		ptr=ptr->next;
	}
	if(ptr == nullptr ) ptrprev = nullptr;
	return ptrprev;
}

查找指定元素的节点:

ListNode* Findvalue(LinkList* plist,ElemType val)
{
	assert(plist != nullptr);
	ListNode* str=Findvalueprev(plist,val);
	if(str != nullptr) {
		str = str->next;
	}
	return str;
}

7.删除指定元素的节点:

void remove(LinkList* plist,ElemType val)
{
	assert(plist != nullptr);
	Erasenext(plist,Findvalueprev(plist,val));
}

删除指定元素的所有节点:

void removeall(LinkList* plist,ElemType val)
{
	assert(plist != nullptr);
	ListNode* p = plist->head;
	for(;p->next != nullptr;)
	{
		if(p->next->data == val) {
			Erasenext(plist,p);
	}else{
		p=p->next;
	}
	}
}

8.清空链表:

void clearList(LinkList* plist)
{
	assert(plist != nullptr);
	while(plist->cursize){
	EraseFrist(plist);
	}
}

9.销毁链表:

void DestroyList(LinkList *plist)
{
	assert(plist != nullptr);
	clearList(plist);
	Freenode(plist->head);
}

10.打印链表:

void PrintList(LinkList* plist)
{
 assert(plist != nullptr);
 ListNode* p = plist->head->next; // first;
 while (p != nullptr)
 {
  printf("%d ", p->data);
  p = p->next;
 }
 printf("\n");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值