C语言实现单链表--详解

单链表

本篇博客主要整理了带头指针的单链表的,初始化,头插,尾插,头删,尾删,在指定位置之后插入数据,查找数据位置,删除指定位置之后的结点,删除指定位置之后的所有结点等功能,并在代码的注释附上了详细的解释,希望可以对读者有所帮助。

链表

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

  1. 单向、双向
  2. 带头、不带头
  3. 循环、非循环

今天我们主要讲一下单链表:
先来看一下单链表的基本构图:
C语言实现单链表--详解_第1张图片

头文件

#pragma once
#include
#include 
#include 
#include 
typedef int SDataType;//类型重定义
typedef  struct  SListNode//定义单链表节点结构体
{
	SDataType  _data;//存放节点的数据
	struct SListNode* _next;//存放下一个节点的指针,指向下一个结构体 因此是struct SListNode*类型
}SListNode;
typedef struct Slist//定义单链表
{
	SListNode* head;//定义指向单链表的头指针
}Slist;
void InitSlist(Slist* plt);//初始化单链表
void SLTPushBack (Slist*plt, SDataType value);//尾插
void SLTPushFront (Slist*plt, SDataType value);//头插
void SLTPopBack(Slist* plt);//尾删
void SLTPopFront(Slist* plt);//头删
SDataType   SLTFind(Slist* plt, SDataType x);//查找节点
void SListInsertAfter(Slist*plt,SDataType pos, SDataType x);//在给定位置之后插入一个新节点
void SListEraseAfter(Slist*plt,SDataType pos);//在删除指定位置之后的节点
void SListPrintf(Slist*plt);//打印数据
void SListEraseAfterAll(Slist*plt,SDataType pos);//在删除指定位置后的所有节点

子函数

#include"SList.h"
Slist lt;//定义一个Slist 的变量 lt;

void InitSlist(Slist* plt)//初始化单链表
{
	assert(plt);
	plt->head=NULL;
	if(plt->head==NULL)
	{
	printf("初始化成功!\n");
	}
	else
	{
		printf("初始化失败!");
	}

}
void SLTPushBack (Slist*plt, SDataType value)//尾插
{      //尾插的基本思想是,先把数据存放到新节点的数据域并把next置空
	//然后找到尾节点插入即可
	
	SListNode* newnode=(SListNode*)malloc(sizeof(SListNode));//为新结点开辟空间
	SListNode*cur=plt->head;
	newnode->_data=value;
	newnode->_next=NULL;
	if(plt->head==NULL)//如果链表为空,直接将头指针指向新结点
	{
		plt->head=newnode;
	}
	else//找到单链表的尾
	{
		while(cur->_next!=NULL)
		{
			cur=cur->_next;
		}
		cur->_next=newnode;//
	}
}
void SLTPushFront (Slist*plt, SDataType value)//头插
{    //和尾插做法一致
	//不过这里要考虑插入的顺序,先将要插入的新结点和原来的头结点链上,
	//再和头指针链上
	
    SListNode*newnode=(SListNode*)malloc(sizeof(SListNode));
	assert(plt);
	newnode->_data=value;
	newnode->_next=NULL;
	newnode->_next=plt->head;
	plt->head=newnode;
}
void SLTPopBack(Slist* plt)//尾删
{
	//首先要找到尾然后进行删除,不过这里有几种特殊的情况
	SListNode* cur=plt->head;
	assert(plt);
	if(cur==NULL)//如果链表为空
	{
		return;
	}
	else if((cur->_next)==NULL)//只有一个数据
	{
		free(cur);
		plt->head=NULL;
	}
	else {
		while((cur->_next->_next)!=NULL)//正常情况找到尾结点的前一个
		{      
			cur=cur->_next;
		}
		//将前一个结点的next 释放掉,然后再置空
		//若果直接释放最后一个导致倒数第二个的next既找不到下一个结点也不为空
		//因此是释放倒数第二个的next,将倒数第二个的next置空
		free(cur->_next);
		cur->_next=NULL;
	}
}
void SLTPopFront(Slist* plt)//头删
{
	//头删也就是把头指针和第一个结点的next链起来,并且释放掉第一个结点
	//但要注意的是先链起来再释放否则找不到第一个结点的next
	assert(plt);
	if(plt->head==NULL)
	{
		return ;
	}
	else
	{
	SListNode*cur=plt->head;
	plt->head=cur->_next;
	free(cur);
	cur=NULL;
	}
}
SDataType   SLTFind(Slist* plt, SDataType x)//查找数据返回位置
 {   
	 int count=1;//定义一个计数器用作位置的返回值
	 SListNode*cur=plt->head;
	 assert(plt&&x);
	 
	 if(plt->head==NULL)
	 {
		 return -1;
	 }
	 if(cur->_data==x&&cur->_next!=NULL)
	 {
		 return 1;//如果第一个就是返回位置1
	 }
	 else
	 {	 
		 while(cur->_next!=NULL)
		 { 
			 if(cur->_data!=x)//不相等计数器就++,并且继续向后走遍历一遍
			 {
				count++;	
				cur=cur->_next;
			 } 
	     }
		  if(cur->_data==x)
		    {
		  	    return count;//找到就返回位置
		    }
		   else
				 return -1;//都没有找到返回-1
     }
}


void SListInsertAfter(Slist*plt,SDataType pos, SDataType x)//在给定位置之后插入一个新结点
{
	SDataType count=1;//设置计数器
	SListNode*cur=plt->head;
	SListNode*newnode=(SListNode*)malloc(sizeof(SListNode));
	newnode->_data=x;
	newnode->_next=NULL;
	while(count!=pos&&cur->_next!=NULL)//找到pos位置的结点
	{
		count++;
		cur=cur->_next;
	}
	if(count==pos)//找到时插入
	{
	  newnode->_next=cur->_next;//先将新结点的next链上前面结点的next
	  cur->_next=newnode;
	}


}
void SListEraseAfter(Slist*plt,SDataType pos)//在删除指定位置之后的节点
{
	SDataType count=1;
	SListNode*cur1=plt->head;
	if(pos==1)//相当于头删
	{
    SListNode*cur=plt->head;
	plt->head=cur->_next;
	free(cur);
	cur=NULL;
	}
	while(count!=pos&&cur1->_next!=NULL)//找到pos位置的结点
	{
		count++;
		cur1=cur1->_next;
	}
	if((pos)==count&&pos!=1)//找到的时候
	{
		SListNode*Next=cur1->_next->_next;//先保存要删除的结点的下一个结点
		free(cur1->_next);//释放要删除的结点
		cur1->_next=NULL;//置空
		cur1->_next=Next;//再将前后链接起来

	}


}
void SListEraseAfterAll(Slist*plt,SDataType pos)//在删除指定位置之后所有的结点
{    //和上一个子函数类似,只不过是将指定位置之后置空
	SDataType count=1;
	SListNode*cur=plt->head;
	assert(plt);
	if(pos==1)
	{
		free(cur->_next);
		cur->_next=NULL;
	}
	while(count!=pos&&cur->_next!=NULL)//找到pos位置的结点
	{
		count++;
		cur=cur->_next;
	}
	if((pos)==count&&pos!=1)
	{
		free(cur->_next);
		cur->_next=NULL;
	}

}

void SListPrintf(Slist*plt)//打印数据
{
	SListNode*cur=plt->head;
    assert(plt);
	while(cur!=NULL)
	{
		printf("%d ",cur->_data);
		cur=cur->_next;
	}
	printf("\n");
}

主函数

#include"SList.h"
 void SListTest1()
{
	Slist lt;//定义一个Slist 的变量 lt;
	//SDataType ret;
   InitSlist(&lt);//初始化单链表//注意需要传地址过来
   SLTPushBack (&lt,1);//尾插
   SLTPushBack (&lt,2);//尾插
   SLTPushBack (&lt,3);//尾插
   SLTPushBack (&lt,4);//尾插
   SLTPushBack (&lt,5);//尾插
   SLTPushFront (&lt, 0);//头插
   //SLTPopBack(<);//尾删
   SListPrintf(&lt);//打印数据
   //printf("\n");
   //SLTPopFront(<);//头删
   //SListPrintf(<);//打印数据
   //ret=SLTFind(<, 7);//查找数据返回位置
   //if(ret>0)
   //{
	  // printf("找到了,位置是:%d\n",ret);
   //}
   //else
   //{
	  // printf("找不到\n");
   //}
   //
   //SListInsertAfter(<,1 ,9);//在给定位置之后插入一个新结点
   SListPrintf(&lt);//打印数据
   //SListEraseAfter(<,3);//在删除指定位置之后的结点
   SListEraseAfterAll(&lt,2);//删除指定位置的所有结点
   SListPrintf(&lt);//打印数据
}
int main()
{
  SListTest1();//测试函数

  system("pause");
}

测试

尾插
C语言实现单链表--详解_第2张图片
头插
C语言实现单链表--详解_第3张图片
尾删
C语言实现单链表--详解_第4张图片
头删
C语言实现单链表--详解_第5张图片
查找位置
C语言实现单链表--详解_第6张图片
在给定位置之后插入一个新节点
C语言实现单链表--详解_第7张图片
删除指定位置之后的结点
C语言实现单链表--详解_第8张图片
删除指定结点之后的所有结点
C语言实现单链表--详解_第9张图片

你可能感兴趣的:(数据结构,C语言)