数据结构单链表的完整代码复习

简介: 引言:1. 注意点和易错点的各种详细注释2.头文件中各个接口的声明3.调试和功能交给你们啦

引言:

单链表目前有的地方容易写出问题来,所以明天再来一遍,没什么问题之后我们就进军双链表

1. 注意点和易错点的各种详细注释

#include"S.h"
//1.打印
void SListPrint(SLTNode* phead)//这个参数不敢不会写(传过来的是一个指针(结构体类型的),所以这边也就是写成一个结构体 类型的指针)
{
  SLTNode* cur = phead;
  while (cur != NULL)//0.这里错了,这个不可以这样放,因为一开始进来的时候,我此时还没有cur->next这个指针嘞
  {
    printf("%d->", cur->data);
    cur = cur->next;
  }
}
//2.新增结点
SLTNode* SListGreateNewnode(SLTDataType x)//1.这个的传参要明白,这个是不需要头指针的,重要有数字就行
{
  SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//2.注意这个不是realloc这里不需要两个参数
  if (newnode == NULL)
  {
    printf("malloc fail\n");
    exit(-1);
  }
  newnode->data = x;
  newnode->next = NULL;
  //这边开完新的结点这边一定要记得把这个结点给返回去
  return newnode;
}
//3.尾插
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
  assert(pphead);
  SLTNode* newnode = SListGreateNewnode(x);
  if (*pphead == NULL)
  {
    *pphead = newnode;
  }
  else
  {
    SLTNode* tail = *pphead;
    //尾插就是要找尾
    while (tail->next)
    {
      tail = tail->next;
    }
    //跳到这里,按照当前逻辑就是找到了
    //此时首先要开辟一个新的结点
    tail->next = newnode;
  /*  newnode->next = NULL;//此时的newnode中已经定义过了,所以不需要再定义
    newnode->data = x;*/
  }
}
//4.尾删  
void SListPoptBack(SLTNode** pphead, SLTDataType x)//完全正确
{
  assert(pphead);
  if (*pphead == NULL)
  {
    return;
  }
  else if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  else
  {
    SLTNode* prev = NULL;
    SLTNode* tail = *pphead;
    while (tail->next != NULL)
    {
      prev = tail;
      tail = tail->next;
    }
    free(tail);
    tail = NULL;
    prev->next = NULL;
  }
}
//4.尾删
void SListPoptBack(SLTNode** pphead, SLTDataType x)//完全正确
{
  //尾删另一种方法
  assert(pphead);
  if (*pphead == NULL)
  {
    return;
  }
  else if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  else
  {
    SLTNode* tail = *pphead;
    while (tail->next->next !=NULL)
    {
      tail = tail->next;
    }
    free(tail->next);
    tail->next = NULL;
  }
}
//5.头插
void SListPushFront(SLTNode** pphead, SLTDataType x)//正确
{
  assert(pphead);
  SLTNode* newnode = SListGreateNewnode(x);
  newnode->next = *pphead;
  //这个位置容易错(少一步),就是没把头还回去
  *pphead = newnode;
}
//6.头删
//void SListPoptFront(SLTNode** pphead, SLTDataType x)
//{
//  assert(pphead);
//
//  if (*pphead == NULL)
//  {
//    printf("node is empty\n");
//    return NULL;
//  }
//  else if ((*pphead)->next == NULL)
//  {
//    free(*pphead);
//    *pphead = NULL;
//  }
//  else
//  {
//    SLTNode* next = NULL;
//    SLTNode* cur = *pphead;
//    next = cur->next;
//    free(*pphead);
//    *pphead = NULL;
//    SLTNode* newnode = SListGreateNewnode(x);
//    newnode = next;
//    //基本步骤完成之后,就是轮到注意点了
//  }
//}
void SListPoptFront(SLTNode** pphead)
{
  assert(pphead);
  if (*pphead == NULL)
  {
    printf("node is empty");
    return;
  }
  else
  {
    SLTNode* next = (*pphead)->next;
    free(*pphead);
    *pphead = next;
  }
}
//7.查找接口
//SLTNode* SListFind(SLTNode** pphead, SLTNode* pos, SLTDataType x)//这步问题很大(没有完全理解)
//{
//  assert(pphead);
//
//  if ((*pphead)->next == NULL)
//  {
//    return *pphead;
//  }
//  SLTNode* tail = *pphead;
//  while (tail->data != x)
//  {
//    tail = tail->next;
//  }
//  //程序来到这个位置说明我找到了
//  return tail;
//}
SLTNode* SListFind(SLTNode* phead, SLTDataType x)//订正,这个函数问题很大(虽然写法很多,但是……)
{
  SLTNode* cur = phead;
  while (cur)
  {
    if (cur->data == x)
    {
      return cur;
    }
    else
    {
      cur = cur->next;
    }
  }
}
//8.任意位置插(pos位置)
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)//基本对
{
  assert(pphead);
  assert(pos);
  //if (*pphead == NULL)//只有一个元素不能按照上面这样写,应该写成下面这个样子
  //{
  //  //此时就是一个头插
  //SLTNode* newnode = SListGreateNewnode(x);
  //newnode->next = *pphead;  //错误的
  //}
  SLTNode* newnode = SListGreateNewnode(x);//订正的
  if (*pphead == pos)
  {
    newnode->next = *pphead;
    *pphead = newnode;
  }
  else
  {
    SLTNode* posPrev = *pphead;
    while (posPrev->next != pos)
    {
      posPrev = posPrev->next;
    }
    /*SLTNode* newnode = SListGreateNewnode(x);*///这步上面有了这边就可以不要
    posPrev->next = newnode;
    newnode->next = pos;
    //基本操作搞定之后就是注意点
  }
}
//8.任意位置插(pos后一个位置)//多了很多不要的,还是没有得到精髓
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
  assert(pphead);
  //if (*pphead == pos)
  //{
  //  SLTNode* newnode = SListGreateNewnode(x);
  //  (*pphead)->next = newnode;
  //  newnode->next = NULL;
  //}
  //SLTNode* tail = *pphead;
  SLTNode* newnode = SListGreateNewnode(x);
  newnode->next = pos->next;
  pos->next = newnode;
  //基本条件写完就是注意点
}
//9.任意位置删除(pos位置)
void SListInsert(SLTNode** pphead, SLTNode* pos)//这几步一直有问题主要是因为没有理解这个pos的意思
{
  assert(pphead);
  assert(pos);
  //if ((*pphead)->next == NULL)//错误写法
  //{
  //  free(*pphead);
  //  *pphead = NULL;
  //}
  if (pos == *pphead)//我的订正
  {
    SLTNode* next = pos->next;
    free(*pphead);
    *pphead = next;
  }
  else
  {
    SLTNode* tail = *pphead;
    SLTNode* next = pos->next;//虽然这步是写对了,但是主要就是还是没有理解pos
    while (tail->next != pos)
    {
      tail = tail->next;
    }
    tail->next = next;
    free(pos);
    pos = NULL;
    //写完基本的就是注意点
  }
}
//10.任意位置删(pos的下一个位置)
//void SListInsert(SLTNode** pphead,SLTNode* pos)//记住这种形式的删除都是可以不需要给头的,因为他已经给了我pos了,我只要在删pos的后面那个位置就行了
//{
//  assert(pphead);
//  assert(pos);
//  SLTNode* tail = *pphead;
//  while (tail->next != pos)
//  {
//    tail = tail->next;
//  }
//  //程序来到这个位置就是说明我已经找到了
//  free(pos->next);
//  pos->next = NULL;
//
//}
void SListInsert(SLTNode* pos)//这个表示的就是一个结点
{
  assert(pos->next);//此处传过来的是pos的位置,所以我只需要判断这个结点中的指针就行
  assert(pos);
  SLTNode* next = pos->next->next;
  free(pos->next);
  pos->next = NULL;
  pos->next = next;
}
//11.销毁
//void SListDestroy(SLTNode** pphead)
//{
//  SLTNode* cur = *pphead;
//  while (cur->next != NULL)
//  {
//    SLTNode* next = cur->next;
//    free(cur);
//    cur = NULL;
//  }
//}
void SListDestroy(SLTNode** pphead)
{
  SLTNode* cur = *pphead;
  while (cur != NULL)
  {
    SLTNode* next = cur->next;
    free(cur);
    cur = next;
  }
  *pphead = NULL;
}

2.头文件中各个接口的声明

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
  SLTDataType data;
  struct SListNode* next;
}SLTNode;
//1.打印接口
void SListPrint(SLTNode* phead);
//2.新增结点接口
SLTNode* SListGreateNewnode(SLTDataType x);
//3.尾插接口
void SListPushBack(SLTNode** pphead, SLTDataType x);
//4.尾删接口
void SListPoptBack(SLTNode** pphead, SLTDataType x);
//5.头插接口
void SListPushFront(SLTNode** pphead, SLTDataType x);
//6.头删接口
void SListPoptFront(SLTNode** pphead, SLTDataType x);
//7.查找接口
SLTNode* SListFind(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//8.任意位置插入(pos位置)
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//9.任意位置插入(pos后一个位置)
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//9.任意位置删除(pos位置)
void SListInsert(SLTNode** pphead, SLTNode* pos);
//10.任意位置删除(pos后一个位置)
void SListInsert(SLTNode** pphead, SLTNode* pos);
//11.销毁接口
void SListDestroy(SLTNode** pphead);


3.调试和功能交给你们啦

主要是明天很神奇的需要练习跳舞,这个就不写了啦

相关文章
|
2天前
|
算法 Java
Java数据结构与算法:双向链表
Java数据结构与算法:双向链表
|
2天前
|
算法 Java
Java数据结构与算法:循环链表
Java数据结构与算法:循环链表
|
2天前
|
算法
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
|
2天前
|
算法
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
|
2天前
|
算法 程序员 数据处理
【数据结构与算法】使用单链表实现队列:原理、步骤与应用
【数据结构与算法】使用单链表实现队列:原理、步骤与应用
|
2天前
|
算法
【数据结构与算法 经典例题】随机链表的复制(图文详解)
【数据结构与算法 经典例题】随机链表的复制(图文详解)
|
2天前
|
算法 C语言
【数据结构与算法 经典例题】链表的回文结构(图文详解)
【数据结构与算法 经典例题】链表的回文结构(图文详解)
|
2天前
|
算法
【数据结构与算法 经典例题】反转链表(图文详解)
【数据结构与算法 经典例题】反转链表(图文详解)
|
2天前
|
算法 C语言
【数据结构与算法 经典例题】返回单链表的倒数第 k 个节点
【数据结构与算法 经典例题】返回单链表的倒数第 k 个节点
|
2天前
|
算法 C语言
【数据结构与算法 经典例题】相交链表求交点
【数据结构与算法 经典例题】相交链表求交点