前面写的单链表结构体是重新设计的。包含头结点(或者头指针)以及链表长度的结构体,而我们通常实现的链表是直接把单链表结点结构体作为单链表来使用的,下面我们给出z这种实现方式,让我们一起来细细体会他们实现之间的区别
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
//#define DEBUG // 调试插桩信息宏
///*
///
/// 带头结点的单链表结构体
///
///*
///*
///
/// 带头结点的单链表结构体
///
///*
typedef int ElemType; // 自定义数据类型
//typedef struct LinkListNode* PLinkListNode; // 链表结点指针域
// 链表结点数据域
typedef struct LinkListNode
{
ElemType m_data; // 数据域
struct LinkListNode *m_next; // 指针域
}LinkListNode;
// 带头结点的单链表
typedef struct LinkListNode 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初始化的单链表
而使用用FinitLinkList来进行后处理
以免发生内存泄漏
*/
void InitLinkList(LinkList *list)
{
list->m_next = NULL; // 初始化只有头结点
list->m_data = 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初始化的单链表
而使用用FinitLinkList来进行后处理
*/
void FinitLinkList(LinkList *list)
{
assert(list->m_next == NULL); // 后处理指针针对空链表
// assert(list->m_data == 0);
if(list != NULL) // 如果此时头结点空间未被销毁
{
free(list);
}
}
/**
void ClearLinkList(LinkList *list)
参数
list : 指向一个链表指针,此处传入表头地址
返回值
无
功能
清空单链表中的所有元素
*/
void ClearLinkList(LinkList *list)
{
while(list->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* FindDataNode(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_data); // 插入的w位置只能在[-1~length]
LinkListNode *pNode = list;
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;
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_next;
int pos = 0;
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* FindDataNode(LinkList *list, ElemType data, int *position
参数
list : 指向一个链表指针,此处传入表头地址
data : 待查找的结点的数据信息
返回值
若成功 返回结点node在链表中的位置
若失败 返回-1
功能
找到数据域为data的结点首次出现的位置并返回结点信息
*/
LinkListNode* FindDataNode(LinkList *list, ElemType data, int *position)
{
LinkListNode *node = list->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_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_data + 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_data++; // 结点数目增加一个
// 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 : 待删除结点的位置
返回值
返回待删除结点的数据域
功能
将单链表的第position个结点删除
*/
ElemType DeleteNode(LinkList *list, int position)
{
assert(list != NULL);
assert(position >=0 && position < list->m_data);
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_data--; // 结点数目减少一个
return delNode;
}
/**
void DeleteNode(LinkList *list, int position)
参数
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_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_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 == 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_data);
if(list->m_data == 0)
{
return ;
}
LinkListNode *pNode = list->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_data; 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 : 指向一个链表指针,此处传入表头地址
返回值
单链表的长度
功能
获取单链表的长度
*/
int LengthLinkList(LinkList *list)
{
return list->m_data;
}
/**
bool IsEmptyLinkList(LinkList *list)
参数
list : 指向一个链表指针,此处传入表头地址
返回值
如果单链表是空表,返回true
否则返回false
功能
获取单链表的长度
*/
bool IsEmptyLinkList(LinkList *list)
{
return (list->m_data == 0);
// return (list->m_head->m_next == NULL);
}
#define LIST_SIZE 7
// main
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; // 带头结点的单链表头指针是list->m_next
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_next);
}
ShowList(&list); // 显示单链表
return EXIT_SUCCESS;
}