11.27 单链表 3

接上次单链表2

尾删:

思路:

11.27 单链表 3_第1张图片

 1.如果直接这样写

void SLtPopBack(SLT** pphead)
{
	SLT* tail = *pphead;
	while (tail->next != NULL)
	{
		tail = tail->next;
	}
	free(tail);
	tail = NULL;
}

则tail指向的是最后一个结点,被释放后,其前面节点的next仍然指向他,并可访问到,会造成非法访问(起前面的结点将成为野指针-指向一块被释放的空间)

2.如果这样写

void SLtPopBack(SLT** pphead)
{
	SLT* tail = *pphead;
	SLT* prev = NULL;
	while (tail->next != NULL)
	{
		prev = tail;
		tail = tail->next;
	}
	free(tail);
	tail = NULL;
	prev->next = NULL;
}

则删除时可以正常进行

11.27 单链表 3_第2张图片

 but

如果删到最后一个

11.27 单链表 3_第3张图片

 4个数据删4次,程序直接崩了

跟上面类似的情况

11.27 单链表 3_第4张图片

因为此处prev的下一个已经为空,-> 为解引用操作,又造成非法访问

so

3. 分三种情况

①直接为空

②有一个结点,第二个为空

③大于等于3结点

void SLtPopBack(SLT** pphead)
{
	//1 .直接为空
	assert(*pphead != NULL);

	//2	.只有一个结点(第二个为空)
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//3	.结点 >= 3
	else
	{
		SLT* tail = *pphead;
		SLT* prev = NULL;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}

同时,最后情况3可以这样写

		SLT* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;

2.头删

11.27 单链表 3_第5张图片

不能上来就free掉plist,因为会找不到下一个

所以先保存头,并指向下一个地址

 再free掉原来的头,再把原来的头指向刚保存的

void SLtPopFront(SLT** pphead)
{
	assert(*pphead != NULL);

	SLT* head = (*pphead)->next;
	free(*pphead);
	*pphead = head;
}

并要考虑到,若链表中无任何节点,*(pphead)->next,又对下一个地址解引用,又非法访问

所以要考虑是否有节点,加入assert / if

3.查找

SLT* SListFind(SLT* phead, SLTDataType x)
{
	SLT* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}

找到之后,可以修改

pos = SListFind(plist, 33);
	if (pos)
	{
		pos->data = 333;
	}

如图,找到33后改为333

4.在pos之前插入x

11.27 单链表 3_第6张图片

分2种情况:

①pos就在头部

此时,相当于头插,而且不能直接用插入,因为newnode->next永远不是pos(newnode)

②pos在其他任何地方

void SListInsert(SLT** pphead, SLT* pos, SLTDateType x)
{
	SLT* newnode = CreatListNode(x);//	创建节点x

	if (*pphead == pos)//如果pos等于头
	{
		//newnode->next = *pphead;	// 直接把新节点的next存入原来的头
		//*pphead = newnode;			// 把新节点的地址放入作为新的头
		SLtPushFront(pphead, x);	//	头插
	}
	else
	{
		SLT* posPrev = *pphead;
		while (posPrev->next != pos)
		{
			posPrev = posPrev->next;
		}
		posPrev->next = newnode;
		newnode->next = pos;
	}
}

5.在pos之后插入x

创建节点,然后pos->next指向新节点的头,新节点的next指向原来pos的next

11.27 单链表 3_第7张图片

void SListInsertAfter(SLT* pos, SLTDateType x)
{
	SLT* newnode = CreatListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

你可能感兴趣的:(数据结构)