链表与内存--头节点的登场和链表分割

上篇写到了链表,后来发现自己对链表的理解还有些偏差,重新做了下链表测试,优化了相关代码。具体可参看前一篇文章链表与内存块
主要改动的地方是:之前理解的链表为一个节点一个节点串联起来,后来查看资料,发现如果给链表增加一个空节点,使用起来会更加方便。也就是说,链表表头的第一个节点只有地址,没有实际数据,当然我们也可以给他填充上一些数据比如链表长度等。从第二个节点开始节点有了地址和数据,我们称第二个节点为头指针。很显然,头节点不一定是头指针,头节点可以没有,但头指针必须有。
[头节点] -> [头指针]->[ ] -> NULL
那么加入头节点之后,代码瞬间就变得统一起来,而且也更加好理解。
如增加一个节点到链表,可以如下定义,可对比之前的文章中的添加节点代码。
下面是增加头节点后的代码,敬请参考。

增加元素到链表
/* 增加一个元素到链表中 
* 	head -- 链表头节点
* 	item -- 要增加的加点
*	Opr  -- 0(增加到头指针) -1(增加到尾指针) >0 增加到对应节点之后
*/
U8 NodeAdd(struct node **head, struct node *item, S8 Oper)
{
	struct node *temp;
        
	/* 头节点为空,链表未分配地址 */
	if (*head == NULL)
	{
		return 0;
	}

	/* 添加到头指针 */
	if (Oper == 0)
	{
		item->next = (*head)->next;
		(*head)->next = item;
		(*head)->data++;
		return 1;
	}
	else if (Oper == -1) /* 添加到尾指针 */
	{
		temp = (*head)->next; /* 获取链表头指针 */
   	 	while(temp)
		{
			if (temp->next == NULL)
			{
				item->next = *head;
				//item->next = NULL; 		/* 先续尾 */
				temp->next = item;		/* 再接头 */
				(*head)->data++;
	        	return 1;
			}
			temp = temp->next;
		}
	}
	else
	{
		temp = (*head)->next; /* 获取链表头指针 */
    	while(temp)
		{
			if (temp->index == Oper)
			{
				item->next = temp->next; 	/* 先续尾 */
				temp->next = item;			/* 再接头 */
				(*head)->data++;
	        	return 1;
			}
			temp = temp->next;
		}
	}
	return 2;//节点索引错误
}
删除链表中节点
/* 在链表中删除指定节点 */
U8 NodeDel(struct node **head, U8 DelIndex)
{
	struct node *nodeforward; /* 查询节点指针 */
	struct node *nodetemp;		/* 暂存节点指针 */

	/* 头节点空 */
	if (*head == NULL)
	{
		return 0;
	}

	nodeforward = (*head); /* 查询指针指向头节点 */

	while(nodeforward->next)
	{
		nodetemp = nodeforward; 
		nodeforward = nodeforward->next;

		if (nodeforward->index == DelIndex)
		{
			nodetemp->next = nodeforward->next;
			(*head)->data--;
			return 1;
		}
	}
	return 2;
}
修改指定节点的值

//修改指定节点中的值
U8 NodeModifyIndex(struct node **head, U8 *data,U8 modifyindex)
{
	struct node *temp;

	if (*head == NULL)
	{
		return 0;
	}

	temp = *head;

	while(temp)
	{
		if (temp->index == modifyindex)//找到指定节点
		{
			memcpy(&temp->data,data,sizeof(temp->data));
			return 1;
		}
		temp = temp->next;
	}
	return 2;//没有找到对应节点
}
将一个链表按顺序分割
/*
* 	将一个链表按照给定值val排序,大于等于val的放在后面,小于val的放在前面
*	链表带头结点: [头结点] -> [头指针] -> [] -> []
*	头结点存放结点个数,索引为0
*/
U8 NodeCut2Parts(struct node **head,U8 val)
{
	struct node *temp = NULL;
	struct node *small = NULL;
	struct node *big = NULL;
	struct node *ptrsmall = NULL; /* 指向small链表各结点的指针 */
	struct node *ptrbig = NULL;	

	small = (struct node *)malloc(sizeof(struct node));
	big = (struct node *)malloc(sizeof(struct node));

	ptrsmall = small;
	ptrbig = big;

	if (*head == NULL)/* 链表为空,头节点 */
	{
		free(small);
		free(big);
		return 0;
	}
	else
	{
		temp = (*head)->next;/* 头指针赋值 */
		
		while(temp)
		{
			if (temp->index < val)
			{
				ptrsmall->next = temp;
				ptrsmall = ptrsmall->next; /* small链表节点指针后移 */
			}
			else
			{
				ptrbig->next = temp;
				ptrbig = ptrbig->next;	/* big链表节点指针后移 */
			}
			temp = temp->next; /* 原链表节点指针后移 */
		}
		/* 将大小链表的最后节点指向NULL */
		ptrsmall->next = NULL; 
		ptrbig->next = NULL;

		ptrsmall->next = big->next; /* 大小链表合并 */
		(*head)->next = small->next;/* 合并后赋值给原链表 */
		free(small);
		free(big);
	}
}

主程序可以用来测试功能
void main()
{
	U8 datamodify = 0xAB;
	struct node *NewNodeList;
	struct node Node[10];


	NewNodeList->data = 0;
	NewNodeList->index = 0;
	NewNodeList->next = NULL;

	/* 给10个节点赋值 */
	for (i=0;i<10;i++)
	{
		Node[i].index = i+1;
		Node[i].data = (U8)(((i+1)&0x0F)|(((i+1)<<4)&0xF0));
		Node[i].next = NULL;
	}

	//1. 分别把Node1,2,3 加入链表
	NodeAdd(&NewNodeList,&Node[0],0);
	NodeAdd(&NewNodeList,&Node[5],0);
	NodeAdd(&NewNodeList,&Node[3],0);
	NodeAdd(&NewNodeList,&Node[8],0);
	NodeAdd(&NewNodeList,&Node[1],-1);

	//GetNodeNum(&NewNodeList);
	
	NodeAdd(&NewNodeList,&Node[6],-1);
	NodeAdd(&NewNodeList,&Node[2],-1);
	NodeAdd(&NewNodeList,&Node[7],-1);
	NodeAdd(&NewNodeList,&Node[4],6);
	NodeAdd(&NewNodeList,&Node[9],1);

	//4. 删除指定节点
	NodeDel(&NewNodeList,2);

	//5. 修改某个节点的值
	NodeModifyIndex(&NewNodeList,&datamodify,1);

	NodeCut2Parts(&NewNodeList,5);
}

v v v v v v

本文为作者原创,请勿转载,转载请联系作者。
点击下方卡片,关注我的公众号,有最新的文章和项目动态。

v v v v v v

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董董灿是个攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值