数据结构模版----单链表SimpleLinkList[带头结点&&面向对象设计思想](C语言实现)

链表中的数据是以节点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示线性表称作线性链表(单链表)

单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。

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



//#define DEBUG				// 调试插桩信息宏

///	版本V0.0.2更新
///	①将InsertNode重新实现为两个函数
//	将数据data插入链表的第position个位置
//	LinkListNode* InsertNode(LinkList *list, int position, ElemType data)
//	将数据data插入链表的pNode结点的下一个位置个位置
//	LinkListNode* AddNode(LinkList *list, LinkListNode *prevNode, ElemType data)

///	②将DelNode重新实现为三个函数
//	删除链表list中第position个指针
//	ElemType DeleteNode(LinkList *list, int position)
//	删除链表list中prevNode结点之后的指针个指针
//	ElemType SubNode(LinkListNode *prevNode)
//	删除链表list中currNode指针所指向的那个结点
//	ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode)

/// ③将FindNode重新实现为三个函数
//	查找到链表list中第position个结点
//	LinkListNode* FindPosNode(LinkList *list, int position);
//	在链表list中找到currNode的前一个结点
//	LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode);
//	判断结点node指向的区域是不是链表中的结点
//	int IsNodeInList(LinkList *list, LinkListNode *node);



///*
///
///	带头结点的单链表结构体
///
///*
typedef int ElemType;		// 自定义数据类型

//typedef struct LinkListNode*	PLinkListNode;			// 链表结点指针域

// 链表结点数据域
typedef struct LinkListNode
{
	ElemType			m_data;			// 数据域
	struct LinkListNode	*m_next;			// 指针域
}LinkListNode;

// 带头结点的单项链表
typedef struct LinkList
{
	LinkListNode	*m_head;				// 链表头结点
	int				m_length;			// 单链表数据结点个数指针域
}LinkList;



///*
///
///	创建和初始化单链表
///
///	创建		LinkList* CreatLinkList(void)
///	初始化	void InitLinkList(LinkList *list)
///*
/**
LinkList* CreatLinkList(void)
参数
	list	:	指向一个链表指针,此处传入表头地址
返回值
	若成功返回创建好的单链表的指针
功能
	开辟一个单链表数据结构,并初始化头结点,然后将创建好的单链表指针返回
注意
	使用CreateLinkList创建的单链表,需要用DestroyLinkList来销毁
	以免发生内存泄漏
*/
LinkList* CreateLinkList(void)
{
	LinkList *list = NULL;
	if((list = (LinkList *)malloc(sizeof(LinkList))) == NULL)		// 开辟单链表的空间
	{	// 开辟失败
        fprintf(stderr, "not enough memory when CREATE LIST...\n");
        exit(EXIT_FAILURE);
	}

	InitLinkList(list);				// 初始化单链表

	return list;
}

/**
void InitLinkList(LinkList *list)
参数
	list	:	指向一个链表指针,此处传入表头地址
返回值
	无
功能
	初始化单链表, 执行以下操作
	①开辟头结点的空间 ②进行必要的初始化[头结点的初始化和单链表结点数目的初始化]
注意
	使用InitLinkList初始化的单链表(初始化时malloc了头结点m_head的空间)
	而使用用FinitLinkList来进行后处理(后处理时free了头结点的m_head空间)
	以免发生内存泄漏
*/
void InitLinkList(LinkList *list)
{
	if((list->m_head = malloc(sizeof(LinkListNode))) == NULL)		// 为头结点开辟空间
	{	// 开辟失败
        fprintf(stderr, "not enough memory when MALLOC HEAD...");
        exit(EXIT_FAILURE);
	}
	list->m_head->m_next = NULL;			// 初始化只有头结点
	list->m_head->m_data = 0;				// 数据元素个数为0
	list->m_length = 0;						// 数据元素个数为0
}


///*
///
///	销毁以及后处理单链表
///
///	销毁用CreateLinkList创建的单链表
///	void DestroyLinkList(LinkList *list)
///
///	后处理单链表,
///	void FinitLinkList(LinkList *list)
///
/// 清空单链表中的所有元素
///	void ClearLinkList(LinkList *list)
///*
/**
void DestroyLinkList(LinkList *list)
参数
	list	:	指向一个链表指针,此处传入表头地址
返回值
	无
功能
	销毁用CreateLinkList创建的单链表,执行以下操作
	①清空单链表	②释放头结点	③释放单链表
注意
	使用CreateLinkList创建的单链表,需要用DestroyLinkList来销毁
	以免发生内存泄漏
*/
LinkList* DestroyLinkList(LinkList *list)
{
	ClearLinkList(list);			// 清空链表
	FinitLinkList(list);			// 销毁头结点
	if(list != NULL)				// 销毁链表的空间
	{
		free(list);
		list = NULL;
	}
}


/**
void FinitLinkList(LinkList *list)
参数
	list	:	指向一个链表指针,此处传入表头地址
返回值
	无
功能
	后处理单链表, 执行以下操作
	①开辟头结点的空间 ②进行必要的初始化[头结点的初始化和单链表结点数目的初始化]
注意
	使用InitLinkList初始化的单链表(初始化时malloc了头结点m_head的空间)
	而使用用FinitLinkList来进行后处理(后处理时free了头结点的m_head空间)
	以免发生内存泄漏
*/
void FinitLinkList(LinkList *list)
{
	assert(list->m_head->m_next == NULL);		// 后处理指针针对空链表
	// assert(list->m_length == 0);
	if(list->m_head != NULL)			// 如果此时头结点空间未被销毁
	{
		free(list->m_head);

		list->m_head = NULL;
		list->m_length = -1;			// 未经初始化的单链表元素个数记为-1
	}
}



/**
void ClearLinkList(LinkList *list)
参数
	list	:	指向一个链表指针,此处传入表头地址
返回值
	无
功能
	清空单链表中的所有元素
*/
void ClearLinkList(LinkList *list)
{
    while(list->m_head->m_next != NULL)
	{
        DeleteNode(list, 0);
	}
}


///*
///
///	查找函数
///
///	查找到链表list中第position个结点
///	LinkListNode* FindPosNode(LinkList *list, int position)
///
///	在链表list中找到currNode的前一个结点
///	LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode)
///
/// 判断结点node指向的区域是不是链表中的结点
///	int IsNodeInList(LinkList *list, LinkListNode *node)
///
///	找到数据域为data的结点首次出现的位置并返回结点信息
///	LinkListNode* FindNodeData(LinkList *list, ElemType data, int *position)
///*
/**
LinkListNode* FindPosNode(LinkList *list, int position)

参数
	list	:	指向一个链表指针,此处传入表头地址
	positon	:	带查找的链表指针的位置
返回值
	若成功返回指向待查找结点的指针
	若失败返回NULL
功能
	查找到链表list中第position个结点
*/
LinkListNode* FindPosNode(LinkList *list, int position)
{
	assert(list != NULL);									// 链表不能为空
	assert(position >= -1 && position < list->m_length);	// 插入的w位置只能在[-1~length]

	LinkListNode 	*pNode	= list->m_head;
    int 			pos 	= -1;

    while(pNode != NULL && pos < position)		// 遍历单链表,找到第position个结点的位置
	{
		pNode = pNode->m_next;
		pos++;
	}

	if(pNode == NULL || pos < position)
	{
		return NULL;
	}
	else
	{
#ifdef DEBUG
		printf("Find the %d point SUCCESS...[%p]\n", position, pNode);
#endif // DEBUG
		return pNode;
	}
}


/**
LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode);

参数
	list		:	指向一个链表指针,此处传入表头地址
	currNode	:	待查找的链表指针的位置
返回值
	若成功返回指向待查找结点的指针
	若失败返回NULL
功能
	在链表list中找到currNode的前一个结点
*/

LinkListNode *FindPrevNode(LinkList *list, LinkListNode *currNode)
{
	assert(list != 	NULL);
	assert(currNode != NULL);

	LinkListNode *pNode = list->m_head;

	while(pNode->m_next != NULL && pNode->m_next != currNode)
	{
		pNode = pNode->m_next;
	}

	if(pNode->m_next == currNode)				// 查找成功
	{
		return pNode;
	}
	else										// 查找失败
	{
		return NULL;
	}
}

/**
int IsNodeInList(LinkList *list, LinkListNode *node)

参数
	list	:	指向一个链表指针,此处传入表头地址
	node	:	指向待查找的结点的指针
返回值
	若成功 返回结点node在链表中的位置
	若失败 返回-1
功能
	判断结点node指向的区域是不是链表中的结点
*/
int IsNodeInList(LinkList *list, LinkListNode *node)
{
	assert(list != NULL);									// 链表不能为空	assert(Node != NULL);									// 待查找的指针不能为空

	LinkListNode 	*pNode	= list->m_head;
    int 			pos 	= -1;

    while(pNode != NULL && pNode != node)		// 遍历单链表,找到第position个结点的位置
	{
		pNode = pNode->m_next;
		pos++;
	}

	if(pNode == NULL)
	{	// 查找成功
		return -1;
	}
	else
	{	// 查找失败
#ifdef DEBUG
		printf("Find the [%p] point in the first %d pointer of the list...\n", fNode, pos);
#endif // DEBUG
		return pos;
	}
}

/**
LinkListNode* FindData(LinkList *list, ElemType data, , int *position)

参数
	list	:	指向一个链表指针,此处传入表头地址
	data	:	待查找的结点的数据信息
返回值
	若成功 返回结点node在链表中的位置
	若失败 返回-1
功能
	找到数据域为data的结点首次出现的位置并返回结点信息
*/
LinkListNode* FindNodeData(LinkList *list, ElemType data, int *position)
{
	LinkListNode *node = list->m_head->m_next;
	int pos = 0;
	while(node != NULL && node->m_data != data)
	{
		node = node->m_next;
		pos++;
	}
	*position = pos;				// 将出现的位置传递回去

	return node;					// 返回结点的信息
}



///*
///
///	插入函数
///
///	将数据data插入链表的prevNode结点的下一个位置个位置
///	LinkListNode *AddNode(LinkList *list, LinkListNode *prevNode, ElemType data)
///
///	将数据data插入链表的第position个位置
///	LinkListNode *InsertNode(LinkList *list, int position, ElemType data)
///*
/**
LinkListNode* AddNode(LinkList *list, LinkListNode *prevNode, ElemType data);
参数
	list		:	指向一个链表指针,此处传入表头地址
	prevNode	:	待插入位置的前一个结点
	data		:	待插入结点的数据
返回值
	无
功能
	将数据data插入链表的prevNode结点的下一个位置个位置
*/
LinkListNode *AddNode(LinkList *list, LinkListNode *prevNode, ElemType data)
{
	assert(prevNode != NULL);						// 插入点不能是空指针

	LinkListNode *newNode = NULL;
	if((newNode = (LinkListNode *)malloc(sizeof(LinkListNode))) == NULL)	// 为新结点开辟空间
	{	// 开辟新结点失败
		fprintf(stderr, "not enough memeory\n");
        exit(EXIT_FAILURE);
	}
	//else
	//{
	// 开辟新结点成功
	newNode->m_data = data;
	newNode->m_next = NULL;

	// 将指针newNode连接在pNode的后面
	newNode->m_next = prevNode->m_next;
	prevNode->m_next = newNode;

	list->m_length++;				// 结点数目增加一个
	list->m_head->m_data++;			// 头结点的数据域同样存储着结点总数
	//}
#ifdef DEBUG
	printf("The new node is inserted after point pointer[%p]\n", pNode);
#endif // DEBUG
	return newNode;
}

/**
void InsertNode(LinkList *list, int position, ElemType data)
参数
	list	:	指向一个链表指针,此处传入表头地址
	positon	:	待插入结点的位置
	data	:	待插入结点的数据
返回值
	无
功能
	将数据data插入链表的第position个位置
*/
LinkListNode *InsertNode(LinkList *list, int position, ElemType data)
{
	assert(list != NULL);
	assert(position >=0 && position < list->m_length + 1);

	LinkListNode *prevNode = FindPosNode(list, position - 1);			// 找到待插入位置的前一个结点
	LinkListNode *newNode = NULL;

	// 下面调用InsertPointNode直接将结点插入到pNode结点后面
	if((newNode = AddNode(list, prevNode, data)) != NULL)	// 将新的结点插入到待插入前一个指针的后面
	{	// 插入成功
		return newNode;								// 返回新插入的结点
#ifdef DEBUG
		printf("Insert the value %d into list at position %d...\n", data, position);
#endif // DEBUG
	}
	else
	{
		return NULL;								// 插入失败返回NULL
	}

//	//	以可以使用下面的代码
//	if((newNode = (LinkListNode *)malloc(sizeof(LinkListNode))) == NULL)	// 为新结点开辟空间
//	{	// 开辟新结点失败
//		fprintf(stderr, "not enough memeory\n");
//        exit(EXIT_FAILURE);
//	}
//	else
//	{	// 开辟新结点成功
//	newNode->m_data = data;
//	newNode->m_next = NULL;
//
//	// 将指针newNode连接在pNode的后面
//	newNode->m_next = prevNode->m_next;
//	prevNode->m_next = newNode;
//
//	list->m_length++;				// 结点数目增加一个
//	list->m_head->m_data++;			// 头结点的数据域同样存储着结点总数
//	}
}


///*
///
///	删除函数
///
///	删除链表list中prevNode结点之后的指针个指针
///	void DeleteNode(LinkList *list, int position)
///
///	删除链表list中prevNode结点之后的指针个指针
///	ElemType SubNode(LinkList *list, LinkListNode *prevNode)
///
///	删除链表list中prevNode结点之后的指针个指针
///	ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode)
///*
/**
void DeleteNode(LinkList *list, int position)
参数
	list	:	指向一个链表指针,此处传入表头地址
	positon	:	待删除结点的位置
返回值
	返回待删除结点的数据域
功能
	删除链表list中prevNode结点之后的指针个指针
*/
ElemType DeleteNode(LinkList *list, int position)
{
	assert(list != NULL);
	assert(position >=0 && position < list->m_length);
	LinkListNode *prevNode = FindPosNode(list, position - 1);			// 找到第position - 1个结点

	// 删除pNode的后一个结点
	LinkListNode *delNode = prevNode->m_next;
	ElemType delElem = delNode->m_data;
	prevNode->m_next = delNode->m_next;
	free(delNode);

	list->m_length--;				// 结点数目减少一个
	list->m_head->m_data--;			// 头结点的数据域同样存储着结点总数

	return delNode;
}

/**
ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode);
参数
	list	:	指向一个链表指针,此处传入表头地址
	positon	:	待删除结点的位置
返回值
	返回待删除结点的数据域
功能
	删除链表list中prevNode结点之后的指针个指针
*/
ElemType SubNode(LinkList *list, LinkListNode *prevNode)
{
	assert(list != NULL);						// 链表不能为空
	assert(prevNode != NULL);						// 待删除结点的前一个位置不能为空
	assert(IsNodeInList(list, prevNode) != -1);	// 待删除位置的前一个结点必须在链表中

	// 删除pNode的后一个结点
	LinkListNode *delNode = prevNode->m_next;
	ElemType delElem = delNode->m_data;
	prevNode->m_next = delNode->m_next;
	free(delNode);

	list->m_length--;				// 结点数目减少一个
	list->m_head->m_data--;			// 头结点的数据域同样存储着结点总数

	return delElem;

}


/**
ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode);
参数
	list	:	指向一个链表指针,此处传入表头地址
	positon	:	待删除结点的位置
返回值
	返回待删除结点的数据域
功能
	删除链表list中prevNode结点之后的指针个指针
*/
ElemType DeleteCurrNode(LinkList *list, LinkListNode *currNode)
{
	assert(list != NULL);							// 链表不能为空
	assert(currNode != NULL);							// 待删除结点的前一个位置不能为空
	assert(IsNodeInList(list, currNode) != -1);	// 待删除的结点必须在链表中

	ElemType delElem = -1;							// 待删除结点的数据域
	LinkListNode *delNode = NULL;					// 指向将要删除的结点的指针

	if(currNode->m_next != NULL)					// 如果待删除结点不是最后一个结点
	{
		// 将currNode的后一个结点delNode作为删除结点,
		delNode = currNode->m_next;
		currNode->m_next = delNode->m_next;			//从链表中删除delNode

		// 并将delNode的数据域保存到delNode中
		delElem = currNode->m_data;					// delElem保存currNode的数据域
		currNode->m_data = delNode->m_data;			// 真正删除的结点其实是currNode下一个结点, 因此用currNode保存下一个结点的数据域
	}
	else											// 否则待删除结点是最后一个结点
	{
		// 直接将最后一个结点删除即可, 应该把其前一个结点的指针域赋值为空
		delNode = currNode;
		// 下面应该将currnNode的前一个结点的指针域赋值为空[时间复杂度O(n)]
		LinkListNode *prevNode = FindPrevNode(list, currNode);
		prevNode->m_next = NULL;
	}
	free(delNode);
	list->m_length--;				// 结点数目减少一个
	list->m_head->m_data--;			// 头结点的数据域同样存储着结点总数

	return delElem;
}


///*
///
///	其他函数
///
///	显示单链表的信息
///	void ShowList(LinkList *list
///
///	删除链表list中prevNode结点之后的指针个指针
///	void SetNode(LinkList *list, int position, ElemType data)
///
///	获取单链表list第position个结点的数据域
/// ElemType GetNode(LinkList *list, int position)
///
///	获取单链表list的长度[即元素个数]
///	int LengthLinkList(LinkList *list)
///
///	判断当前链表是否是空链表
///	bool IsEmptyLinkList(LinkList *list)
///*
/**
void ShowLinkList(LinkList *list)
参数
	list	:	指向一个链表指针,此处传入表头地址
返回值
	无
功能
	显示单链表的信息
*/
void ShowList(LinkList *list)
{
// assert(list->m_head != NULL)
	if(list->m_head ==  NULL)			//  单链表可能没有被初始化
	{
		fprintf(stderr, "you can't SHOW the list without the list INITLINKLIST...\n");
		return ;
	}


	printf("there are %d data in list\n", list->m_length);
	if(list->m_length == 0)
	{
		return ;
	}

	LinkListNode *pNode = list->m_head->m_next;			// 从头指针开始遍历

	while(pNode != NULL)								//开始遍历单链表
	{
		printf("%d  ", pNode->m_data);
        pNode = pNode->m_next;
	}
	printf("\n");

//	ElemType data;
//	for(int pos = 0; pos < list->m_length; pos++)
//	{
//		data = GetNode(list, pos);
//		printf("%d  ", data);
//	}
//	printf("\n");
}

/**
void SetNode(LinkList *list, int position, ElemType data)
参数
	list	:	指向一个链表指针,此处传入表头地址
	positon :	待修改的结点的数据
	data	:	待更正的新数据域
返回值
	无
功能
	修改单链表list第position个结点的数据域为data
*/
void SetNode(LinkList *list, int position, ElemType data)
{
	LinkListNode *pNode = FindPosNode(list, position);		// 找到单链表的第position个结点

	pNode->m_data = data;
}


/**
ElemType GetNode(LinkList *list, int position
参数
	list	:	指向一个链表指针,此处传入表头地址
	positon :	待查询的结点的位置
返回值
	获取到的结点数据
功能
	获取单链表list第position个结点的数据域
*/
ElemType GetNode(LinkList *list, int position)
{
	LinkListNode *pNode = FindPosNode(list, position);		// 找到单链表的第position个结点

	return pNode->m_data;
}

/**
int LengthLinkList(LinkList *list)
参数
	list	:	指向一个链表指针,此处传入表头地址
	positon :	待查询的结点的位置
返回值
	获取到的结点数据
功能
	获取单链表list的长度[即元素个数]
*/
int LengthLinkList(LinkList *list)
{
	return list->m_length;
}


/**
bool IsEmptyLinkList(LinkList *list)
参数
	list	:	指向一个链表指针,此处传入表头地址
返回值
	如果单链表是空表,返回true
	否则返回false
功能
	判断当前链表是否是空链表
*/
bool IsEmptyLinkList(LinkList *list)
{
	return (list->m_length == 0);
	// return (list->m_head->m_next == NULL);
}




#define LIST_SIZE 7
// 主函数
int main(void)
{
	int pos;

	printf("TEST 1...\n");
	LinkList *plist = CreateLinkList( );				// 创建单链表
	for(int pos = 0; pos < LIST_SIZE; pos++)			// 循环向单链表中插入数据
	{
		InsertNode(plist, pos, pos + 1);
	}
	ShowList(plist);									// 插入结束后显示单链表的信息

	DeleteNode(plist, 0);								// 删除第一个元素
	ShowList(plist);
	DeleteNode(plist, 1);								// 删除第二个元素
	ShowList(plist);

	ClearLinkList(plist);								// 将单链表清空
	ShowList(plist);
	DestroyLinkList(plist);								// 将单链表销毁
	plist = NULL;

	printf("\n\nTEST 2...\n");
	LinkList list;
	InitLinkList(&list);								// 初始化单链表
	for(int pos = 0; pos < LIST_SIZE; pos++)			// 训话向单链表中插入数据
	{
		InsertNode(&list, pos, pos + 1);
	}
	ShowList(&list);									// 显示单链表
	ClearLinkList(&list);								// 清空单链表
//	FinitLinkList(&list);		// ERROR== list->m_head->m_next == NULL
	ShowList(&list);

	printf("\n\nTEST 3...\n");
	LinkListNode *prevNode = list.m_head;
	LinkListNode *addNode = NULL;
	for(int pos = 0; pos < LIST_SIZE; pos++)
	{
		if((addNode = AddNode(&list, prevNode, pos + 1)) != NULL)
		{
            prevNode = addNode;
		}
	}
	ShowList(&list);
	while(IsEmptyLinkList(&list) != true)			// 循环删除单链表中的数据
	{
		DeleteCurrNode(&list, list.m_head->m_next);
	}
	ShowList(&list);									// 显示单链表

	return 	EXIT_SUCCESS;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值