数据结构基础——链表

1.链表的特点

(1)申请的空间可以不连续

(2)链表访问不方便

(3)插入、删除不需要移动元素,比较方便

头结点:数据域无效

首结点:第一个数据域有效的结点

尾结点:指针域无效

空链表:既是头结点又是尾结点

2 .链表的分类

有没有头结点:

带头结点的链表和不带头结点的链表

一般使用的是带头结点的链表

指针域是双向还是单项

单项链表和双向链表

尾结点是否指向头结点:

循环链表和不循环链表

3. 定义数据元素的类型

typedef int data_type;

4. 定义链表中结点的数据类型

typedef struct linknode

{
       data_type data;//数据域

       struct linknode *pNext;//指针域

}Link;

5.对链表的操作

5.1插入元素

对链表的插入可以分为三种插入方式,分别为:头插法、尾插法和中间插入

  这是插入前的准备:创建一个新的节点,并为其赋值

    //创建新的节点
    Link *pNew = (Link *)malloc(sizeof(Link));
	if(NULL == pNew)
	{
		return MALLOCERROR;
	}
	memset(pNew,0,sizeof(Link));
	//将数据赋值给新建节点的data域
	pNew->data = item;

头插法:

        顾名思义,头插法是将新的元素插入到头结点的后面。

       先将头结点与首节点联系断开,将首节点的地址(存放在头结点的指针域)赋给要插入的新节点的指针域,这样子新节点就和后面的所有节点连接了起来,起到了保护后面所有节点的作用;

        然后将新节点的地址赋值给头结点的指针域,覆盖掉原本存放的首节点的地址,这样操作就完成了对链表的头结点插入元素

//头插法
	case HEAD:
		//保护后面的所有节点
		if(pHead->pNext != NULL)
		{
			pNew->pNext = pHead->pNext;
		}
		//新节点插入
		pHead->pNext = pNew;
		break;

尾插法:

        顾名思义,尾插法就是将新的节点插入到链表的的最后面,也就是尾节点之后。

它的做法和头插法一样,只是要如何才能找到尾结点

        首先,我们定义一个指针变量,并将其初始化为头结点;

        然后我们可以发现,只有尾结点的指针域为NULL,则可以执行循环,每当我们所定义的指向头节点的指针变量的指针域不为NULL的时候,就让其后移一位,直到循环结束,找到了指针域为NULL的尾结点,然后将新节点插入到之后,并将新节点的指针域置为NULL

   Link *pTail = NULL; 
//尾插法
	case TAIL:
		pTail = pHead;
		while(pTail->pNext != NULL)
		{
			pTail = pTail->pNext;
		}
		//插入新节点
		pTail->pNext = pNew;
		break;

中间插入:

中间插入就是将数据元素插入到链表的中间位置

首先,定义一个指针变量,初始化为头结点,需要找到插入节点的前一个节点

因为,要插入的位置的前一个节点保存了要插入位置的后一个节点的地址

知道了后面节点的地址才能对其进行操作

    Link *pPre = NULL;
    int i = 0;
    //中间插入
	default:
		pPre = pHead;
		pTail = pHead->pNext;
		if(NULL == pTail)
		{
			return LINKNULL;
		}
		while(pTail->pNext != NULL && i < pos-1)
		{
			pPre = pTail;
			pTail = pTail->pNext;
			i++;
		}
		pNew->pNext = pPre->pNext;
		pPre->pNext = pNew;

5.2 显示链表

        对于链表的显示,由于其物理地址不连续,不能通过下标遍历,需要指针的移动来访问链表的每一个节点。

思路如下:链表的结束遍历标志为遍历到尾结点,即当一个节点的指针域为NULL的时候,就找到了尾结点,链表的遍历也就完成了

 代码如下:

//显示链表
//参数:链表的首地址
//返回值:成功返回ok,失败返回原因
int showLink(Link *pHead)
{
	//入参判断
	if(NULL == pHead)
	{
		return LINKNULL;
	}
	//定义一个结构体指针,指向链表的首地址
	Link *pTemp = NULL;
	pTemp = pHead->pNext;
	//循环遍历直到pTemp->pNext为空
	while(pTemp != NULL)
	{
		printf("%-4d",pTemp->data);
		pTemp = pTemp->pNext;
	}
	printf("\n");
	return ok;
}

5.3 根据位置删除链表中的元素

删除元素与插入元素思想一致,都是需要先要找到要操作的元素的位置,后续操作与插入相似

代码如下:
 

//根据位置删除链表中的元素
//参数一:链表的首地址 Link *pHead
//参数二:要删除的位置 int pos
//参数三:保存要删除的数据
//返回值:成功返回ok,失败返回原因
int deleteLink(Link *pHead,int pos,data_type *pData)
{
	//入参判断
	if(NULL == pHead)
	{
		return LINKNULL;
	}
	//定义一个结构体变量,保存要删除的节点的首地址
	Link *pDel = NULL;
	Link *pPre = NULL;
	int i = 0;
	switch(pos)
	{
		//头删法
		case HEAD:
			//找到要删除的节点
			pDel = pHead->pNext;
			//保存要删除的数据
			*pData = pDel->data;
			//保护后面的所有节点
			pHead->pNext = pDel->pNext;
			//释放pDel
			free(pDel);
			pDel = NULL;
			break;
		//尾删法	
		case TAIL:
			//找到尾节点和他前面的一个节点
			pPre = pHead;
			pDel = pHead->pNext;
			if(NULL == pDel)
			{
				return LINKNULL;
			}
			while(pDel->pNext != NULL)
			{
				//同时移动两个指针
				pPre = pDel;
				pDel = pDel->pNext;
			}
			//保存要删除的数据
			*pData = pDel->data;
			//pPre的指针域置为空
			pPre->pNext = NULL;
			//释放pDel
			free(pDel);
			pDel = NULL;
			break;
		//中间插入
		default:
			pPre = pHead;
			pDel = pHead->pNext;
			if(NULL == pDel)
			{
				return LINKNULL;
			}
			//将两个指针同时向后移动pos-1次
			while(i < pos-1)
			{
				pPre = pDel;
				pDel = pDel->pNext;
				i++;
			}
			//保存要删除的数据
			*pData = pDel->data;
			//保护后面的所有节点
			pPre->pNext = pDel->pNext;
			//释放pDel 
			free(pDel);
			pDel = NULL;
	}
	return ok;
}

5.4 销毁链表

当使用完链表后,就需要对其进行销毁,释放内存

思想:使用头删法的思想,对链表中的节点挨个进行删除,直到为空链表

此时只剩下头结点,再将头结点free释放,指针置空

//销毁链表
//参数:链表的首地址的地址
int destroyLink(Link **pLink) //pLink=&pHead -> *pLink=pHead
{
	//入参判断
	if(NULL == *pLink)
	{
		return LINKNULL;
	}
	while(1)
	{
		//对链表中的数据挨个删除
		//找到要删除的节点
		Link *pDel =( *pLink)->pNext;
		if(NULL == pDel)
		{
			break;
		}
		//保护好要删除节点后面的所有节点
		(*pLink)->pNext = pDel->pNext;
		//释放pDel
		free(pDel);
		pDel = NULL;
	}
	//释放头节点
	free(*pLink);
	*pLink = NULL;
	return ok;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值