链表的学习,要多画图,分析其中的逻辑关系,便于理解
下面是对单链表所有操作的代码以及详细注释,便于复习
目录
我们对【无头+单向+非循环】链表实现增删查改的功能分别进行代码实现,并对步骤尽可能进行详细分析。
// 单链表中的常规操作
// 单链表尾插
// 注意:并不是所有的方法都要在头文件中声明
// 一般只要将其他用户需要调用的方法在头文件中声明
- // 单链表节点的定义
- typedef struct SListNode
- {
- DataType data; // 节点中的值域
- struct SListNode* next; // 下一个节点的地址
- }SListNode;
-
-
- ///
- // 单链表中的常规操作
- // 单链表尾插
- // 注意:并不是所有的方法都要在头文件中声明
- // 一般只要将其他用户需要调用的方法在头文件中声明
- void SListPushBack(SListNode** pplist, DataType x);
-
- // 单链表的尾删
- void SListPopBack(SListNode** pplist);
-
- // 单链表的头插
- void SListPushFront(SListNode** pplist, DataType x);
-
- // 单链表头删
- void SListPopFront(SListNode** pplist);
-
- // 单链表查找
- SListNode* SListFind(SListNode* plist, DataType x);
-
- // 单链表在pos位置之后插入x
- // 分析思考为什么不在pos位置之前插入?
- void SListInsertAfter(SListNode* pos, DataType x);
-
- // 单链表删除pos位置之后的值
- // 分析思考为什么不删除pos位置?
- void SListEraseAfter(SListNode* pos);
-
- void SListDestroy(SListNode** plist);
-
-
- // 测试链表
- void TestSList();
链表内部自己实现的时候要使用的方式
用户可以不用知道,该方法不需要在头文件中声明
- SListNode* BuySListNode(DataType x)
- {
- SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
- if (NULL == newNode)
- {
- printf("创建节点失败!!!\n");
- exit(0); // 暴力方式处理
- }
-
- newNode->data = x;
- newNode->next = NULL;
- return newNode;
- }
pplist内部现在保存的时候实参plist的地址
*pplist ===> 实参plist
- void SListPushBack(SListNode** pplist, DataType x)
- {
- assert(pplist); // pplist是空:链表不存在
-
- // 空链表---需要让pplist指向刚刚插入的新节点
- if (NULL == *pplist)
- {
- *pplist = BuySListNode(x);
- }
- else
- {
- // pplist的链表不为空
- // 1. 找到原链表中的最后一个节点
- SListNode* cur = *pplist;
- while (cur->next)
- {
- // 获取cur的下一个节点
- // cur++; // 注意下一个节点是通过next指针域获取
- cur = cur->next;
- }
-
- // 2. 插入新节点
- cur->next = BuySListNode(x);
- }
- }
- void SListPopBack(SListNode** pplist)
- {
- assert(pplist); // 保证:pplist指向实参plist
-
- // 1. 空链表
- if (NULL == *pplist)
- return;
- else if (NULL == (*pplist)->next)
- {
- // 2. 链表中只有一个节点
- free(*pplist);
- *pplist = NULL;
- }
- else
- {
- // 3. 链表中有多个节点(至少是2个)
- // a. 找到最后一个节点并保存其前一个节点
- SListNode* cur = *pplist;
- SListNode* prev = NULL; // 保存cur的前一个节点
- while (cur->next)
- {
- prev = cur;
- cur = cur->next;
- }
-
- // cur是最后一个节点 prev刚好是cur的前一个
- free(cur);
- prev->next = NULL;
- }
-
- }
- void SListPrint(SListNode* plist)
- {
- SListNode* cur = plist;
- while (cur)
- {
- printf("%d--->", cur->data);
- cur = cur->next;
- }
-
- printf("NULL\n");
- }
/将x插入到第一个节点之前----插入成功后x就是链表中第一个节点

- //时间复杂度0(1)
- void SListPushFront(SListNode** pplist, DataType x)
- {
- //将x插入到第一个节点之前----插入成功后x就是链表中第一个节点
- assert(pplist);
-
- //申请一个新的节点
- SListNode* newNode = BuySListNode(x);
-
- if (*pplist == NULL) //链表为空
- {
- *pplist = newNode;
- }
- else
- {
- newNode->next = *pplist;
- *pplist = newNode;
- }
- }

- void SListPopFront(SListNode** pplist)
- {
- assert(pplist);
-
- //空链表直接返回
- if (NULL == *pplist)
- {
- return;
- }
-
- //只有一个节点
- else if (NULL == (*pplist)->next)
- {
- free(*pplist);
- *pplist = NULL;
- }
-
- //多个节点, delNode为要删除的节点
- else
- {
- SListNode* delNode = *pplist;//把第一个节点定义为要删除的节点
- *pplist = delNode->next; //让*pplist指向下一个节点
- free(delNode);
- }
- }
//遍历整个链表,将x与结点中的值域进行比较,相等,直接改节点地址
//如果不相等,继续往后便利 cur = cur->next,直到都没有,返回null
- SListNode* SListFind(SListNode* plist, DataType x)
- {
- //遍历整个链表,将x与结点中的值域进行比较,相等,直接改节点地址
- //如果不相等,继续往后便利 cur = cur->next,直到都没有,返回null
- SListNode* cur = plist;
- while (cur != NULL)
- {
- if (x == cur->data)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
//不带头节点的单链表,新节点无法插入到pos之前,而且我们不知道链表的第一个节点,无法遍历
//无法知道pos的前一个是谁,所以只能插入到pos之后

-
- void SListInsertAfter(SListNode* pos, DataType x) //任意位置插入
- {
- SListNode* newNode = NULL;
- if (NULL == pos)
- return;
-
- newNode = BuySListNode(x);
- newNode->next = pos->next;
- pos->next = newNode;
- }
// 单链表删除pos位置之后的值
- // 单链表删除pos位置之后的值
- // 分析思考为什么不删除pos位置?
- void SListEraseAfter(SListNode* pos) //任意位置的删除,实际删除pos之后的节点
- {
- SListNode* delNode = NULL;
- //pos不为空且不是最后一个节点
- if (pos == NULL || pos->next == NULL)
- return;
-
- delNode = pos->next;
- if (NULL == delNode)
- return;
-
- pos->data = delNode->data;
- pos->next = delNode->next;
- free(delNode);
- }
- int SListSize(SListNode* plist) //当前链表中所有的节点计数
- {
- SListNode* cur = plist;
- int count = 0;
- while (cur)
- {
- count++;
- cur = cur->next;
- }
-
- return count;
- }
- void SListDestroy(SListNode** pplist)//单链表的销毁
- {
- assert(pplist);
- SListNode* cur = *pplist;
- while (cur)
- {
- *pplist = cur->next;
- free(cur);
- cur = *pplist;
- }
- *pplist = NULL;
- }