#include <iostream>
using namespace std;
int main()
{
/*结点一般是在堆上申请空间的,申请的空间的地址在堆区上是“随机分配”的,
即空间的地址是随机的,
这也是为什么每一个结点的地址不一定相互连续*/
typedef int SListType;
typedef struct SListNode
{
SListType data;
struct SListNode *next;//这里必须要用struct,而不能用 typedef,因为这是在函数体内部
}SListNode;
//以下实现的均为:单向不带头不循环链表
//创建新结点:
SListNode* BuySListNode(SListType x)//注意该函数的参数是单链表当中的数据域
{
SListNode *node = (SListNode *)malloc(sizeof(SListNode));
node->data = x;
node->next = NULL;
return node;
}
//链表的尾插:
void SListPushBack(SListNode **pplist, SListType x)
{
SListNode *newnode = BuySListNode(x);//这里直接传入实际参数即可,无需连同类型一并传入
if (*pplist == NULL)
{
*pplist = newnode;//传二级指针的目的便是为了空链表的地址能够 真正的 指向 newnode
}
else
{
SListNode *tmp = *pplist;//目的是对传入的参数不作修改
while (tmp->next != NULL)//这里不要忘掉在pplist的后面加上->next,因为null永远在尾结点的下一个位置
{
tmp = tmp->next;
}
tmp->next = newnode;//将新结点链接到原有链表之后
/*pplist->data = x; //这二者的实现已经在创建新结点的函数中被实现过,无需重复实现
pplist->next = NULL;*/
}
}
//链表的头插:
void SListPushFront(SListNode **pplist, SListType x)
{
SListNode *newnode = BuySListNode(x);
/*if (*pplist == NULL)//不同于链表的尾插,链表的头插无需对传入的链表是否为空链表进行判断
{
*pplist = newnode;
}
else
{
SListNode *tmp = *pplist;
*pplist = newnode;
*pplist->next = tmp;
}*/
newnode->next = *pplist;//这里的 newnode 即为该链表的头结点指针
*pplist = newnode;
}
//链表的尾删:
void SListPopBack(SListNode **pplist)
{
SListNode *cur = *pplist,*tmp = NULL;
if (*pplist == NULL)//这里如果不分情况讨论的话,则会对内存空间造成二次free,从而出错
{
cout << "该链表为空,无需进行尾删操作" << endl;
return;
}
else if ((*pplist)->next == NULL)//注意这里存在的优先级问题,-> 的优先级大于 *
{
/*这里讨论传入的链表长度为1的原因是:
在下面的链表长度 > 1 的代码实现中,程序不会进入while循环,
所以tmp的值为随机值,
就会引发报错*/
free(*pplist) = NULL;
*pplist = NULL;
}
else
{
while (cur->next != NULL)
{
tmp = cur;
cur = cur->next;
}
tmp->next = NULL;
free(cur);
cur = NULL;
}
//链表的头删:
void SListNodePopFront(SListNode **pplist)
{
SListNode *tmp = (*pplist)->next;//不要忽略了这里 * 与 -> 的优先级
free(*pplist);
*pplist = tmp;
}
//查找链表的结点:
SListNode *SListFind(SListNode *pplist, SListType x)
{
SListNode *cur = *pplist;
while (cur->next != NULL)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL; //不要忽略了在链表中没有找到的情况
}
//对链表中的其中一个结点进行后插
void SListInsertAfter(SListNode *pos, SListType x)//因为有pos的地址,所以这里无需传入整个链表的地址
{
//法一:
/*SListNode *tmp = pos->next;
pos->next = BuySListNode(x);
pos->next->next = tmp;*/
//法二:就要注意下面代码的先后顺序问题
SListNode *newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
//对链表中的其中一个结点进行前插:
/*注意:只要用到BuySLListNode()函数的地方,就得创建一个指针变量去存放这个新结点的地址*/
void SListPushFront(SlistNode **pplist,SListNode *pos, SListType x)//此时就要传入整个链表的地址,因为这是前插,需要对链表进行遍历
{
SlistNode *newnode = BuySListNode(x);
if (pos == *pplist)
{
//此时相当于头插
SListPushFront(pos, x);
}
else
{
SListNode *cur = *pplist, *tmp = NULL;
while (cur != pos) //因为有 while 循环条件的限制,所以要对传入链表的长度分情况讨论
{
tmp = cur;
cur = cur->next;
}
tmp->next = newnode;
newnode->next = pos;
}
}
//对某结点进行后删
void SListPopBack(SListNode **pplist , SListNode *pos)
{
if (pos->next == NULL)//此时无需进行删除,因为这是给定结点的后删
{
return;
}
else
{
pos->next = pos->next->next;
free(pos->next);
}
}
//销毁链表(也需要逐个去释放结点)
void SListDestroy(SListNode **pplist)
{
SListNode *cur = *pplist;
while (cur != NULL)
{
SListNode *tmp = cur->next;//使用一个临时变量去存储下一个结点的地址
free(cur);
cur = tmp;
}
*pplist = NULL;
}
}
}
【数据结构】单向不带头结点 非循环链表的 增,删,查,改 的实现
最新推荐文章于 2023-06-27 10:11:28 发布