单链表的基本操作(C语言版)

ListNode.h

#define _CRT_SECURE_NO_WARNING 1

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

typedef int DataType;

typedef struct ListNode
{
	struct ListNode* _pNext; //指向链表中下一个结点
	DataType data; //当前节点中保存的元素
}Node,*PNode;

void ListNodeInit(PNode* pHead); //链表的初始化
void ListNodePushBack(PNode* pHead,DataType data);//链表的尾插
void ListNodePopBack(PNode* pHead);//尾删
void ListNodePushFront(PNode* pHead,DataType data);//链表的头插
void ListNodePopFront(PNode* pHead);//链表的头删

//在链表中查找值为data的元素,找到后返回值为data的结点
PNode ListNodeFind(PNode pHead,DataType data);

//在pos位置插入值为data的结点
void ListNodeInsert(PNode* pHead,PNode pos,DataType data);

//删除pos位置的结点
void ListNodeErase(PNode* pHead,PNode pos);

//获取链表中值为data的结点
int ListNodeSize(PNode pHead);

//判断链表是否为空
int ListNodeEmpty(PNode pHead);

//销毁链表
void ListNodeDestroy(PNode* pHead);

//打印链表
void ListNodePrint(PNode pHead);

ListNode.c

#define _CRT_SECURE_NO_WARNING 1

#include "ListNode.h"

//单链表初始化  将链表头指针赋空
void ListNodeInit(PNode* pHead)//*pHead指向的是外部实参的地址
{
	assert(pHead);//断言链表是否存在
	*pHead = NULL;
}

//创建新结点
PNode BuyNewNode(DataType data)
{
	PNode NewNode = (PNode)malloc(sizeof(Node));
	if(NULL == NewNode)
	{
		assert(0);
		return NULL;
	}
	NewNode->data = data;
	NewNode->_pNext = NULL;
	return NewNode;
}


//链表的尾插
void ListNodePushBack(PNode* pHead,DataType data)
{
	PNode pCur = NULL;
	assert(pHead);//断言链表是否存在
	if(NULL == *pHead)
	{
		*pHead = BuyNewNode(data);//如果为空就让链表头结点指向新节点
		return;
	}

		pCur = *pHead;
		//找到最后一个结点
		while(pCur ->_pNext)
		{
			pCur = pCur->_pNext;
		}
		pCur->_pNext = BuyNewNode(data);	
}

//链表的尾删
void ListNodePopBack(PNode* pHead)
{
	PNode pCur = *pHead;
	PNode pPre = *pHead;
	assert(pHead);
	if(NULL == *pHead)
	{
		printf("链表已空无法删除!!!\n");
		return;
	}

	//1.只有一个结点
	if(pCur->_pNext == NULL)
	{
		free(*pHead);
		*pHead = NULL;
		return;
	}

	//2.有多个结点
	while(pCur->_pNext)
	{
		pPre = pCur;//每走一步保存一下前一个结点直到找到倒数第二个结点
		pCur = pCur->_pNext;
	}
	free(pCur->_pNext);
	pPre->_pNext = NULL;

}



//链表的头插
void ListNodePushFront(PNode* pHead,DataType data)
{
	PNode ptr = NULL;
	assert(pHead);
	//1.链表为空
	if(NULL == *pHead)
	{
		*pHead = BuyNewNode(data);
		return;
	}
	//2.链表不为空
	ptr = *pHead;//先保存第一个结点的地址
	*pHead = BuyNewNode(data);//头指针指向新节点
	(*pHead)->_pNext = ptr;//将新的头指针的_pNext指向原来的头指针ptr
}

//链表的头删
void ListNodePopFront(PNode* pHead)
{
	PNode ptr = NULL;
	assert(pHead);
	if(NULL == *pHead)
	{
		printf("链表已空无法删除!!!\n");
		return;
	}
	//1.只有一个结点
	if( (*pHead)->_pNext == NULL)
	{
		free(*pHead);
		*pHead = NULL;
		return;
	}
	//2.有多个结点
	ptr = *pHead;//保存头结点地址
	*pHead = (*pHead)->_pNext;//头指针指向他后面的一个节点地址
	free(ptr);
}

//在链表中查找值为data的元素,找到后返回值为data的结点
PNode ListNodeFind(PNode pHead,DataType data)
{
	PNode pCur = pHead;
	if(NULL == pHead )
	{
		printf("链表为空无法查找!!!\n");
		return NULL;
	}
	while( (pCur) && (pCur->data !=data) )//pCur不为空且pCur中的值不是要查找data则进入循环
	{
		pCur = pCur->_pNext;
	}
	//1.pCur遍历后仍为空证明链表中没有data
	if(NULL == pCur)
	{
		printf("链表中无data!!!\n");
		return NULL;
	}
	else
		return pCur;
}


//在pos位置插入值为data的结点
void ListNodeInsert(PNode* pHead,PNode pos,DataType data)
{
	PNode pCur = *pHead;
	assert(pHead);
	//1.链表为空
	if(NULL == *pHead)
	{
		//1)若插入的位置和头结点地址不同,那么是非法的,插入失败
		if(pos == *pHead)
		{
			*pHead = BuyNewNode(data);
			return;
		}
		else
		{
			printf("非法插入!!!\n");
			return;
		}
	}
	//2.链表不为空
	if(pos == *pHead) //1)插入位置与头结点地址相等
		ListNodePushFront(pHead,data);
	else  //2)插入位置不在头结点位置
	{
		while( (pCur) && (pCur->_pNext != pos) )
		{
			pCur = pCur->_pNext;
		}
		if(pCur == NULL)
		{
			printf("找不到该节点无法插入!!!\n");
			return;
		}
		else
		{
			PNode NewNode = NULL;
			DataType tmp;

			NewNode = BuyNewNode(data);
			NewNode->_pNext = pos->_pNext;
			pos->_pNext = NewNode;

			tmp = pos->data;
			pos->data = data;
			NewNode->data = tmp;
		}
	}

}

//删除pos位置的结点
void ListNodeErase(PNode* pHead,PNode pos)
{
	PNode pPre = *pHead;
	assert(pHead);
	if(NULL == pHead || NULL == pos)
	{
		printf("链表为空无法删除!!!\n");
		printf("pos位置为空删除失败!!!\n");
		return;
	}
	//1.只有一个结点
	if( (*pHead)->_pNext == NULL)
	{
		if(*pHead == pos)
		{
			free(pos);
			*pHead = NULL;
			return;
		}
		else
			return;
	}
	//2.多个结点
	if(*pHead == pos)//1)pos位置是头结点
	{
		*pHead = (*pHead)->_pNext;
		free(pos);
		return;
	}
	//2)pos位置不是头结点
	while( (pPre) && (pPre->_pNext !=pos) && (pos) )
	{
		pPre = pPre->_pNext;
	}
	if( (pPre == NULL) || (pos == NULL) )
		return;
	else
	{
		pPre->_pNext = pos->_pNext;
		free(pos);
	}
}


//获取链表中值为data的结点
int ListNodeSize(PNode pHead)
{
	int count = 0;
	while(pHead)
	{
		pHead = pHead->_pNext;
		count++;
	}
	return count;
}

//判断链表是否为空
int ListNodeEmpty(PNode pHead)
{
	if(pHead)
		return 1;
	return 0;
}

//销毁链表
void ListNodeDestroy(PNode* pHead)
{
	PNode pNext = *pHead;
	PNode pCur = *pHead;
	assert(pHead);
	if(NULL == *pHead)
	{
		printf("链表为空无法销毁!!!\n");
		return;
	}
	while(pCur)
	{
		pNext = pCur->_pNext;
		free(pCur);
		pCur = pNext;
	}
	*pHead = NULL;
}

//打印链表
void ListNodePrint(PNode pHead)
{
	PNode ptr = pHead;
	if(NULL == pHead)
		return;
	while(ptr)
	{
		printf("%d--->", ptr->data);
		ptr = ptr->_pNext;
	}
	printf("NULL\n");
}

test.c

#define _CRT_SECURE_NO_WARNING 1

#include "ListNode.h"

int main()
{
	Node List;
	PNode pHead = &List;
	ListNodeInit(&pHead);// 链表的初始化
	ListNodeEmpty(pHead);
	ListNodeInsert(&pHead,pHead,32);
	ListNodePrint(pHead);
	ListNodePushFront(&pHead,1);
	ListNodePrint(pHead);
        ListNodePushBack(&pHead, 1);//尾插
        ListNodePushBack(&pHead, 2);
	ListNodePushBack(&pHead, 6);
        ListNodePushBack(&pHead, 3);
	ListNodePushBack(&pHead, 6);
	ListNodePushBack(&pHead, 4);
	ListNodePushBack(&pHead, 5);
	ListNodePrint(pHead);
        ListNodePopBack(&pHead);//链表的尾删
	ListNodePrint(pHead);
	ListNodePopFront(&pHead);//链表的头删
	ListNodePrint(pHead);

	ListNodeFind(pHead,6);//查找值为data的元素
	ListNodePrint(pHead);

	ListNodeInsert(&pHead,pHead->_pNext->_pNext,28);
	ListNodePrint(pHead);
	ListNodeErase(&pHead,pHead->_pNext);
	ListNodePrint(pHead);
	
	ListNodeSize(pHead);
	ListNodePrint(pHead);
	ListNodeDestroy(&pHead);
	ListNodePrint(pHead);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/ijn842/article/details/79996006
今日推荐