链表基本操作

链表:

     就是用一组任意的存储单元来存放线性表的元素,这组存储单元可以是连续的,也可以是不连续的,甚至可以是分布在任何位置。

首先定义一个结构体:

typedef int DataType;
 
typedef struct ListNode
{
	DataType data;
	struct ListNode* next;
}ListNode,*pNode;

结点包括两个域:

  • 数据域:用来存储节点的值
  • 指针域:用来存储数据元素的直接后继的地址信息

单链表的基本操作:

LinkList.h

#include<stdio.h>
#include<stdlib.h>

typedef int DataType;
typedef struct Node
{
	int _data;
	struct Node* _next;
}Node,*PNode;

//创建新结点
PNode BuyNewNode(DataType data);

// 尾插 
void SListPushBack(PNode* pHead, DataType data);

// 尾删 
void SListPopBack(PNode* pHead);

// 头插 
void SListPushFront(PNode* pHead, DataType data);

// 头删 
void SListPopFront(PNode* pHead);

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

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

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

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

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

// 链表遍历
void PrintNode(PNode pHead);

LinkList.c

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>
#include"LinkList.h"

PNode BuyNewNode(DataType data)
{
	PNode _new = (PNode)malloc(sizeof(Node));
	if (NULL == _new)
	{
		printf("内存申请失败\n");
		return NULL;
	}

	_new->_data = data;
	_new->_next = NULL;
	return _new;
}

// 尾插操作函数
void SListPushBack(PNode* pHead, DataType data)
{
	PNode _new = NULL;
	// 参数检验
	assert(pHead);

	_new = BuyNewNode(data);
	if (NULL == _new)
	{
		return;
	}
	else
	{
		// 申请到了新节点
		if (NULL == (*pHead))
		{
			// 如果单链表是空的话,让头指针直接指向新节点
			*pHead = _new;
		}
		else
		{
			// 链表非空
			PNode pCur = NULL;
			pCur = (*pHead);

			// 找链表的尾
			while (!(pCur->_next == NULL))
			{
				pCur = pCur->_next;
			}

			// 链接起来
			pCur->_next = _new;
		}
	}
}

// 尾删操作函数
void SListPopBack(PNode* pHead)
{
	PNode pCur = NULL; // 
	PNode pPre = NULL; // 用来保存当前节点前一个节点

	// 参数检验
	assert(pHead);

	pCur = *pHead;
	pPre = pCur;

	// 找单链表的尾,并用pPre保存前一个节点
	while (!(pCur->_next == NULL))
	{
		pPre = pCur;
		pCur = pCur->_next;
	}

	pPre->_next = NULL; // 找到尾之后直接让pPre->_next赋空
	free(pCur); // 释放掉从单链表摘下的节点
	pCur = NULL; // 避免野指针
}

// 头插操作函数
void SListPushFront(PNode* pHead, DataType data)
{
	PNode _new = NULL;

	// 参数检验
	assert(pHead);

	_new = BuyNewNode(data);
	if (NULL == _new)
	{
		return;
	}
	else
	{
		// 成功申请到新节点
		if (*pHead == NULL)
		{
			// 空链表 直接让头指针指向新节点
			*pHead = BuyNewNode(data);
			return;
		}
		// 链表非空 进行头插
		_new = BuyNewNode(data);
		_new->_next = *pHead;
		*pHead = _new;// 修改头指针
	}
}

// 头删操作函数
void SListPopFront(PNode* pHead)
{
	PNode pCur = NULL;

	// 参数检验
	assert(pHead);

	pCur = *pHead;
	if (NULL == pCur)
	{
		printf("链表为空\n");
		return;
	}
	// 单链表非空 
	*pHead = pCur->_next; // 让头指针指向头的_next域
	free(pCur); // 释放pCur
	pCur = NULL; // 避免野指针
}

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

	// 参数检验
	assert(pHead);

	pCur = pHead;
	// 遍历单链表 查找值为data的元素
	while (pCur != NULL)
	{
		if (pCur->_data == data)
		{
			return pCur; // 找到了返回
		}
		pCur = pCur->_next; // pCur后移
	}

	return NULL; // 找不到返回NULL
}

// 在pos位置插入值为data的结点 
void SListInsert(PNode* pHead, PNode pos, DataType data)
{
	PNode pPre = NULL;
	PNode pCur = NULL;
	PNode _new = NULL;

	// 参数检验
	assert(pHead);

	pCur = *pHead;
	pPre = pCur;

	if (pCur->_next == NULL)
	{
		// 链表为空
		if (pCur == pos)
		{
			// 头插
			_new = BuyNewNode(data);
			if (_new == NULL)
			{
				return;
			}
			else
			{
				pHead = &_new;
			}
		}
		else
		{
			// 链表位置不合法
			printf("pos位置不合法\n");
			return;
		}
	}
	// 链表不为空
	while (pCur != NULL)
	{
		if (pos == pCur)
		{
			_new = BuyNewNode(data);
			if (_new == NULL)
			{
				return;
			}
			else
			{
				_new->_next = pPre->_next;
				pPre->_next = _new;
			}
			return;
		}
		else
		{
			pPre = pCur;
			pCur = pCur->_next;
		}
	}
	// 已经遍历完了单链表 仍没找到pos位置
	printf("pos位置不合法\n");
	return;
}

// 删除pos位置的结点 
void SListErase(PNode* pHead, PNode pos)
{
	PNode pCur = NULL;
	PNode pPre = NULL;

	// 参数检验
	assert(pHead);

	pCur = *pHead;
	pPre = pCur;
	if (pCur == NULL)
	{
		printf("链表为空!!!\n");
		return;
	}

	while (pCur != NULL)
	{
		if (pos == pCur)
		{
			pPre->_next = pCur->_next;
			free(pCur);
			pCur = NULL;
			return;
		}
		else
		{
			pPre = pCur;
			pCur = pCur->_next;
		}
	}
	// 已遍历单链表
	printf("pos位置不合法\n");
	return;
}

// 判断链表是否为空  为空返回1 不为空返回0
int SListEmpty(PNode pHead)
{
	if (pHead == NULL)
	{
		return 1;
	}
	return 0;
}

// 销毁链表 
void SListDestroy(PNode* pHead)
{
	PNode p = NULL;
	PNode q = NULL;
	// 参数检验
	assert(pHead);

	p = *pHead;
	while (p != 0)
	{
		// 不是链尾时
		q = p->_next; // 让q指向头节点的后继节点
		free(p);
		p = q; // 让p和q都指向后继节点
	}

	*pHead = NULL; // 将头指针赋空
}
// 链表遍历
void PrintNode(PNode pHead)
{
	PNode pCur = NULL;
	// 参数检验
	assert(pHead);

	pCur = pHead;
	printf("单链表中所有元素:");

	while (pCur != NULL)
	{
		printf("%d->", pCur->_data);
		pCur = pCur->_next;
	}
	printf("NULL\n");
}

1、测试单链表尾插、尾删操作

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include"LinkList.h"

void TestNodePushBack_PopBack()
{
	PNode pHead = NULL; // 头指针,并初始化
	SListPushBack(&pHead, 1); // 尾插元素
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 3);
	SListPushBack(&pHead, 4);
	PrintNode(pHead); // 遍历打印单链表

	SListPopBack(&pHead); // 尾删一个元素
	PrintNode(pHead); // 遍历打印单链表

	SListDestroy(&pHead); // 销毁单链表
}

int main()
{
	TestNodePushBack_PopBack();
	system("pause");
}

2、测试单链表头插、头删操作

//测试头插头删
void TestNodePushFront_PopFront()
{
	PNode pHead = NULL; // 头指针,并初始化
	SListPushFront(&pHead, 4); // 头插元素
	SListPushFront(&pHead, 3);
	SListPushFront(&pHead, 2);
	SListPushFront(&pHead, 1);
	PrintNode(pHead); // 遍历打印单链表

	SListPopFront(&pHead); // 头删一个元素
	PrintNode(pHead); // 遍历打印单链表

	SListDestroy(&pHead); // 销毁单链表

}

int main()
{
	//TestNodePushBack_PopBack();
	TestNodePushFront_PopFront();
	system("pause");
}

3、测试单链表查找、指定位置插入、指定位置删除操作

void TestNodeFind_Insert_Erase()
{
    PNode pHead = NULL;
    PNode ret_Find = NULL;
    SListPushBack(&pHead, 1);
    SListPushBack(&pHead, 2);
    SListPushBack(&pHead, 4);
    PrintNode(pHead);

    ret_Find = SListFind(pHead, 4);
    SListInsert(&pHead, ret_Find, 3);
    PrintNode(pHead);

    SListErase(&pHead, ret_Find);
    PrintNode(pHead);

    SListDestroy(&pHead); // 销毁单链表

}

int main()
{
	//TestNodePushBack_PopBack();
	//TestNodePushFront_PopFront();
	TestNodeFind_Insert_Erase();
	system("pause");
}

为了避免内存泄漏,在使用完单链表之后一点要销毁。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值