【数据结构】单链表的实现与操作

介绍:

单链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。本文将介绍如何实现单链表,并提供常用的操作函数。

代码实现:

  1. 节点的定义和创建 在头文件中,定义了节点结构体SListNode,包含数据成员data和指向下一个节点的指针next。节点的创建通过BuySListNode函数实现,该函数动态申请一个节点,并将数据x赋值给节点的data成员。

    // 动态申请一个节点
    SListNode* BuySListNode(SLTDateType x) {
    	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
    	if (newnode == NULL) {
    		printf("Fail malloc!\n");
    		exit(-1);
    	}
    	newnode->data = x;
    	newnode->next = NULL;
    }

  2. 单链表的打印 SListPrint函数用于打印单链表的所有节点的数据。它通过遍历链表,依次输出每个节点的数据。

    // 单链表打印
    void SListPrint(SListNode* plist) {
    	SListNode* cur = plist;
    	while (cur) {
    		printf("%d", cur->data);
    		cur = cur->next;
    	}
    	printf("NULL\n");
    }

  3. 单链表的尾插 SListPushBack函数用于在单链表的末尾插入一个节点。它接受一个指向链表头指针的指针pplist和数据x作为参数。首先判断链表是否为空,如果为空,则直接将新节点插入链表头;否则,找到链表的末尾节点,将新节点插入到其后面。

    // 单链表尾插
    void SListPushBack(SListNode** pplist, SLTDateType x) {
    	SListNode* newnode = BuySListNode(x);
    
    	if (*pplist == NULL) {
    		// 改变的结构体的指针,所以要用二级指针
    		*pplist = newnode;
    	}
    	else {
    		SListNode* tail = *pplist;
    		while (tail) {
    			// 改变的结构体,用结构体的指针即可
    			tail = tail->next;
    		}
    		tail->next = newnode;
    	}
    
    }

  4. 单链表的头插 SListPushFront函数用于在单链表的头部插入一个节点。它接受一个指向链表头指针的指针pplist和数据x作为参数。首先创建一个新节点,并将数据x赋值给新节点的data成员。然后将新节点的next指针指向原链表的头节点,最后将链表的头指针指向新节点。

    // 单链表的头插
    void SListPushFront(SListNode** pplist, SLTDateType x) {
    	SListNode* newnode = BuySListNode(x);
    	//把pplist所指向的结构体地址存入newnode->next里面,pplist里面存newnode的地址
    	newnode->next = *pplist;
    	*pplist = newnode;
    }

  5. 单链表的尾删 SListPopBack函数用于删除单链表的末尾节点。它接受一个指向链表头指针的指针pplist作为参数。首先判断链表是否为空,如果为空,则直接返回;否则,找到倒数第二个节点,将其next指针置空,并释放最后一个节点的内存空间。

    // 单链表的尾删
    void SListPopBack(SListNode** pplist) {
    	//空
    	assert(*pplist);
    
    	//一个节点
    	if ((*pplist)->next == NULL) {
    		free(*pplist);
    		*pplist = NULL;
    	}
    	//多个节点
    	else {
    		//SLTNode* tailPrev = NULL;
    		//SLTNode* tail = *pphead;
    		//while (tail->next)
    		//{
    		//	tailPrev = tail;
    		//	tail = tail->next;
    		//}
    
    		//free(tail);
    		tail = NULL;
    		//tailPrev->next = NULL;
    
    
    		SListNode* tail = *pplist;
    		while (tail->next->next) {
    			tail = tail->next;
    		}
    		free(tail->next);
    		tail->next = NULL;
    	}
    }

  6. 单链表的头删 SListPopFront函数用于删除单链表的头节点。它接受一个指向链表头指针的指针pplist作为参数。首先判断链表是否为空,如果为空,则直接返回;否则,将链表的头指针指向第二个节点,并释放原头节点的内存空间。

    // 单链表头删
    void SListPopFront(SListNode** pplist) {
    	assert(*pplist);
    
    	SListNode* newhead = (*pplist)->next;
    	free(*pplist);
    	*pplist = newhead;
    }

  7. 单链表的查找 SListFind函数用于在单链表中查找指定的数据x。它接受一个指向链表头节点的指针plist和数据x作为参数。通过遍历链表,逐个比较节点的data成员与x的值,如果相等则返回该节点的指针;如果遍历完整个链表都没有找到相等的节点,则返回NULL。

    // 单链表查找
    SListNode* SListFind(SListNode* plist, SLTDateType x) {
    	SListNode* cur = plist;
    	while (cur) {
    		if (cur->data == x) {
    			return cur;
    		}
    		cur = cur->next;
    	}
    	return NULL;
    }

  8. 单链表的插入 SListInsertAfter函数用于在指定位置pos之后插入一个新节点。它接受一个指向位置pos的指针和数据x作为参数。首先创建一个新节点,并将数据x赋值给新节点的data成员。然后将新节点的next指针指向pos节点的next指针指向的节点,最后将pos节点的next指针指向新节点。

    // 单链表在pos位置之后插入x
    void SListInsertAfter(SListNode* pos, SLTDateType x) {
    	assert(pos);
    	SListNode* newnode = BuySListNode(x);
    
    	newnode->next = pos->next;
    	pos->next = newnode;
    }
  9. SListInsert实现了在单链表中插入一个新节点的功能。函数SListInsert接受一个指向链表头指针的指针pphead、一个指向要插入位置的节点指针pos,以及要插入的数据x作为参数。首先,代码使用断言来确保传入的指针参数不为空,以确保代码的安全性。

    接下来,代码判断如果要插入的位置pos是链表的头节点,即*pphead == pos,则调用SListPushFront函数将新节点插入到链表的头部。

    如果要插入的位置pos不是链表的头节点,则需要先找到要插入位置的前一个节点。代码使用一个指针prev来遍历链表,直到找到pos的前一个节点为止。然后,创建一个新节点newnode,并将要插入的数据x赋值给新节点的data成员。接着,将前一个节点prevnext指针指向新节点newnode,将新节点的next指针指向要插入的位置pos,这样就完成了节点的插入操作。

    通过这段代码,我们可以看出,在单链表中插入一个新节点的操作需要考虑两种情况:要插入的位置是链表的头节点和要插入的位置是其他节点。通过遍历链表找到要插入位置的前一个节点,并进行相应的指针操作,可以实现节点的插入。

    //在pos位置插入x
    void SListInsert(SListNode** pphead, SListNode* pos, SLTDateType x) {
    	assert(pphead);
    	assert(pos);
    
    	if (*pphead == pos) {
    		SListPushFront(pphead, x);
    	}
    	else {
    		SListNode* prev = *pphead;
    		while (prev->next != pos) {
    			prev = prev->next;
    		}
    		SListNode* newnode = BuySListNode(x);
    		prev->next = newnode;
    		newnode->next = pos;
    	}
    }

  10. 单链表的删除 SListEraseAfter函数用于删除指定位置pos之后的节点。它接受一个指向位置pos的指针作为参数。首先将pos节点的next指针指向下下个节点,然后释放被删除节点的内存空间。

    // 单链表删除pos位置之后的值
    void SListEraseAfter(SListNode* pos) {
    	assert(pos);
    
    	//检查pos是否是尾节点
    	assert(pos->next);
    
    	SListNode* posAfter = pos->next;
    	pos->next = posAfter->next;
    	free(posAfter);
    	posAfter = NULL;
    }
  11. 实现了在单链表中删除指定位置的节点的功能。函数SLTErase接受一个指向链表头指针的指针pphead和一个指向要删除位置的节点指针pos作为参数。

    首先,代码使用断言来确保传入的指针参数不为空,以确保代码的安全性。

    接下来,代码判断如果要删除的位置pos恰好是链表的头节点,即pos == *pphead,则调用SListPopFront函数将链表的头节点删除。

    如果要删除的位置pos不是链表的头节点,则需要先找到要删除位置的前一个节点。代码使用一个指针prev来遍历链表,直到找到pos的前一个节点为止。然后,将前一个节点prevnext指针指向要删除位置的下一个节点,以跳过要删除的节点。接着,使用free函数释放要删除的节点的内存空间,完成节点的删除操作。

    通过这段代码,我们可以看出,在单链表中删除指定位置的节点的操作需要考虑两种情况:要删除的位置是链表的头节点和要删除的位置是其他节点。通过遍历链表找到要删除位置的前一个节点,并进行相应的指针操作和内存释放,可以实现节点的删除。

    //删除pos位置
    void SLTErase(SListNode** pphead, SListNode* pos)
    {
    	assert(pphead);
    	assert(pos);
    
    	if (pos == *pphead)
    	{
    		SListPopFront(pphead);
    	}
    	else
    	{
    		SListNode* prev = *pphead;
    		while (prev->next != pos)
    		{
    			prev = prev->next;
    		}
    
    		prev->next = pos->next;
    		free(pos);
    		//pos = NULL;
    		;
    	}
    }

    通过对上述函数的介绍,我们可以看出,单链表的操作需要注意边界条件的处理。在使用这些函数时,需要确保链表的正确性,并及时释放不再使用的节点的内存空间,以避免内存泄漏。

总结:

本文介绍了单链表的实现和常用操作,包括节点的创建、插入、删除以及查找等。通过对头文件代码的解析,详细说明了每个函数的功能和使用方法。希望本文能够帮助读者理解和应用单链表的基本操作,提升编程能力。 

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值