【数据结构与算法(c语言)】线性表--单链表

本文详细介绍了单链表的概念,包括结点结构、头指针和数据对象类型,以及涉及的基本操作,如初始化链表、销毁链表、插入结点、删除结点、访问元素和遍历链表。同时讨论了单链表的优缺点。
摘要由CSDN通过智能技术生成

一 概念

可以用一组任意的存储单元存储线性表的数据元素(a1 a2 a3 … an)

单链表(Single Linked List): n个结点链接成一个链表,即为线性表的链式存储结构,每个结点中只包含一个指针域

在这里插入图片描述

结点(Node) : 数据元素的存储映像。它包含两个域:数据域和指针域。

在这里插入图片描述

数据域(Data Domain): 结点中存储数据元素信息的域。

指针域(Pointer Domain): 结点中存储下一个存储位置的域 指针(pointer):指针域中存储的信息。

头指针(Header Pointer):链表中第一个结点的存储位置 ,如果有头结点,则存储头结点的地址。 单链表一般就是以头指针的名字来命令。如LinkList * list。

头结点(Header Node):单链表中的第一个结点前的预设的结点。数据域内不存储任何信息,指针域存储单链表中第一个结点的位置。

二 数据对象的类型

结点类型 LNode

typedef struct Node
{
	ElemType  data ;	        /*节点数据, */
	struct LNode * next;		/*指向下一个节点的指针 */

} LNode;			/*定义节点类型,并定义一个指向节点的指针 LinkList,作为线性表的开始*/

头指针类型 LinkList

typedef struct Node  *LinkList; // 用Linklist 定义的变量,就是头指针,也就是链表的名称

宏定义

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0


typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */

三 基本操作

3.1 初始化链表 InitList

原型: Status InitList(LinkList * list)
说明: 初始化链表,为头结点申请地址,如果申请成功,将头结点地址赋给头指针 list。
返回: 初始化成功,返回 1;失败,返回 0。

Status InitList(LinkList * list)
{
	if(*list=(LNode*)malloc(sizeof(LNode)==NULL))  //申请一个Lnode大小的内存作为 头结点,并将头结点的地址给list,一个空链表list自	此	就形成 
	return ERROR;
	(*list)->next=NULL; /*没有数据节点,所以将next 设置为NULL */
	return OK;
} 

3.2 销毁链表 DestoryList

原型 :void DestoryList(LinkList * list)
说明:毁链表list,将列表中包括头结点的所有结点的内存全部释放

 /*销毁链表list,包括头结点的地址也释放*/
void DestoryList(LinkList * list)
{	
	LNode * nodePtr, *tempNodePtr; //定义两个指针,指针nodePtr用来作为循环的游标,指针tempNodePtr用来将nodePtr传递过来的地址 释放内存
	nodePtr=*list; /*从头结点开始释放*/
	while(nodePtr !=NULL)
	{
		tempNodePtr = nodePtr; 	/* 先将地址存放到临时指针中 */
		nodePtr = nodePtr->next;  /* 指向下一个*/
	        free(tempNodePtr);      /* 释放地址 */
	}
	
	*list=NULL;	/* 地址都释放完了,最后list置NULL,防止野指针 */
}

3.3 插入结点 ListInsert

原型 : Status ListInsert(LinkList list,int i,ElemType elem)
说明 : 在链表list中的第i个位置插入结点,结点的数据为elem
返回: 插入成功,返回1;插入失败,返回 0

  /*在list的第i个位置插入元素elem*/
 Status ListInsert(LinkList  list,int i,ElemType elem)
{
	 int j=1;
	 //定义两个指针,指针nodePtr用来作为循环的游标,指针newNodePtr用来保存元素elem;
	 LNode * nodePtr,*newNodePtr;
	 nodePtr =list; /*定义一个Node指针,初始值指向头结点*/
	 while( j<i && nodePtr != NULL )     /*寻找第i个结点,当j小于i(还没有到i的位置),  当nodePtr不为空且  */
	 {
		 nodePtr = nodePtr->next; 
		 ++j;				//++j 和上面一行代码 在一个循环中,说明 j每增加1,nodePtr指向就往后移一个位置。
	 }
	 if(nodePtr==NULL) /*到结尾了也没有找到第i个位置 */
		 return ERROR; 
	 newNodePtr=(LNode *) malloc(sizeof(LNode));	 /*为结点申请内存*/
	 if(newNodePtr==NULL)
		 return ERROR;
	 newNodePtr->data=elem;
	 newNodePtr->next=nodePtr->next;
	 nodePtr->next=newNodePtr;
	 return OK;
 }

3.4 删除结点 ListDelete

原型 : Status ListDelete(LinkList list,int i,ElemType * elemPtr)
说明:在list中找到第i个结点,将结点中数据存放到elemPtr中,删除该结点
返回: 删除成功,返回1;删除失败,返回 0

  /*在list中删除第i个元素,并将第i个元素存放到elemPtr指针中*/
 Status ListDelete(LinkList  list,int i,ElemType * elemPtr) 
{
	int j=1;
	
	LNode * nodePtr, *nextNodePtr;
	nodePtr=list; //这里之所以用notePtr=list头结点的指针,而不是notePtr=list->next第一个节点指针
		      //如果使用后者,找到第i个元素,正好是notePtr指向的位置,那么找到位置的前驱元素就没有变量指向了,就没法修改前驱的next了
	while (j<i && nodePtr->next!= NULL)	// 当j<i时说明没有找到
	{
		nodePtr = nodePtr->next;
		++j;
	}
	if(nodePtr->next == NULL)   /*说明已经是最后一个节点了*/
 	    return ERROR;
	nextNodePtr=nodePtr->next;
	*elemPtr=nextNodePtr->data;
	nodePtr->next=nextNodePtr->next;
	free(nextNodePtr);
	return OK;
} 

3.5 访问元素 Visit

原型 : Status Visit(ElemType elem)
说明: 对elem操作,具体什么操作可以根据需要修改,本示例中是打印elem的值

/*对elem操作,具体什么操作可以根据需要修改,本示例中是打印elem的值*/
Status Visit(ElemType elem){
	printf("%d\t",elem);
}

3.6 遍历链表 ListTraverse

原型 :Status ListTraverse(LinkList list, Status(*Visit) (ElemType elem) )
说明 :遍历链表list,第二个参数是一个函数指针,这样可以更换其他函数,本例中为遍历打印。

/*遍历线性表,并对每一个元素调用Visit函数,一旦Visit()失败,这遍历失败 */
Status ListTraverse(LinkList list, Status(*Visit) (ElemType elem) ){

 	LNode * nodePtr=list->next;
	while(nodePtr!=NULL)	
	{  
	  (*Visit)(nodePtr->data);
	   nodePtr=nodePtr->next;
	}
	printf("\n");
	return OK;
}

完整源码下载

结束语 单链表的优缺点

优点:

  1. 根据需要分配内存空间,不浪费内存空间
  2. 插入和删除速度快,时间复杂度为O(1)

缺点:
查找慢,时间复杂度为O(1)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值