目录
- typedef int SLTDataType;
- typedef struct SListNode
- {
- SLTDataType data;
- struct SListNode* next;
- }SLTNode;
为了往后使用数据类型的变换,这里通过typedef 给int换了一个名字,后面我们要换其他的数据类型可以直接吧第一行的int换成你想要的类型。
结构体内data储存数据,next储存下一个节点的地址。
我们接下来创建一个节点。
- SLTNode* BuyNode(SLTDataType x)
- {
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- if (newnode == NULL)//当内存申请失败了需要报错并停止运行
- {
- perror("malloc fail");
- exit(-1);
- }
- newnode->data = x;
- return newnode;
- }
我们需要用到一个SLTNode *类型的函数,因为我们要返回创建节点的地址。
这样我们就可以创建一个链表并在里面插入数据了
- int main()
- {
- SLTNode* plist = NULL;
- phead = BuyNode(1);
- }
phead表示为头结点。
- void PushFront(SLTNode** pphead, SLTDataType x)
- {
- assert(pphead);
- SLTNode *newnode=BuyNode(x);
- newnode->next = *pphead;
- *pphead = newnode;
- }
这里要注意的是,用到了二级指针,之所以要用二级指针是因为:我们需要改变phead的值,所以我们必须要把plist的地址传进来。
这里需要分情况讨论:1、链表非空。2、链表为空。
当链表非空的时候,我们只需要找到尾节点,然后接上新节点就可以了。
但当链表为空的时候,我们就要让头指针指向新节点(需要改变头指针phead),所以还是需要用到二级指针。
- void SlistPushBack(SLTNode** pphead, SLTDataType x)
- {
- assert(pphead);
- SLTNode* newnode = BuyNode(x);
- if (*pphead == NULL)
- *pphead = newnode;
- else
- {
- //找到尾节点
- SLTNode* tail=*pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
- tail->next = newnode;
- }
- }
这里我们设置了一个del变量储存将要删除的节点,每次删除节点我们都要free掉这个节点,不然会有内存泄露的风险。
- void SListPopFront(SLTNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- SLTNode* del = *pphead;
- *pphead = (*pphead)->next;
- free(del);
- del = NULL;
- }
- void SListPopBack(SLTNode** pphead)
- {
- assert(pphead);
- if (*pphead == NULL)
- return;
- //一个节点
- //多个节点
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL;
-
- }
- else
- {
- SLTNode* prev = NULL;
- SLTNode* tail = *pphead;
- while (tail->next != NULL)
- {
- prev = tail;
- tail = tail->next;
- }
- prev->next = NULL;
- free(tail);
- tail = NULL;
- }
- }
因为尾结点需要找到为节点的前一个节点,并将其next值设置为NULL,所以需要分情况讨论。
- void SLTPrint(SLTNode* phead)
- {
- if (phead = NULL)
- return;
- SLTNode* cur = phead;
- while (cur)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
与上面的删除同理,链表的节点都是malloc出来的,养成好习惯,把每个malloc的空间的返回给系统避免资源浪费。
- void SLTistDestory(SLTNode** pphead)
- {
- assert(pphead);
- SLTNode* cur = *pphead;
- while (cur)
- {
- SLTNode* next = cur->next;
- free(cur);
- cur = next;
- }
- *pphead = NULL;
- }
最后记得把phead指向NULL(也就是*pphead),避免野指针的产生。
注意它的返回类型是节点的指针型,在没找到节点时返回NULL。
- SLTNode* SListFind(SLTNode* phead, SLTDataType x)
- {
- if (phead == NULL)
- return;
- SLTNode* cur=phead;
- while (cur)
- {
- if (cur->data == x)
- return cur;
- cur = cur->next;
- }
- return NULL;
- }
我们需要通过上面的find函数,找到我们想在哪个元素前插入的位置(pos)。我们需要找到pos亲一个节点prev,然后再把新节点插入prev节点与pos节点之间。
- void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
- {
- assrtt(pphead);
- assert(pos);
- if (*pphead == pos)
- {
- SListPopFront(x);
- }
- else
- {
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- prev = prev->next;
- SLTNode* newnode = BuyNode(x);
- newnode->next = pos;
- prev->next = newnode;
- }
- }
因为单向链表只能从前往后查找,所以我们需要从头结点一个个往下找,才能找到插入的位置。
但是如果你想在某个元素后面插入数据的话,只需要往下找一个就行了。
- void SListInsertAfter(SLTNode* pos, SLTDataType x)
- {
- assert(pos);
- SLTNode* next = pos->next;
- SLTNode* newnode = BuyNode(x);
- newnode->next = next;
- pos->next = newnode;
-
- }
需要分情况讨论,我这里用了两个指针,当链表只有一个元素的时候不需要两个指针,所以需要分情况讨论。
- void SListErase(SLTNode **pphead,SLTNode* pos)
- {
- assert(pphead);
- assert(pos);
- SLTNode* prev=*pphead;
- if (pos == prev)
- {
- *pphead = pphead->next;
- free(pos);
- pos = NULL;
- }
- else
- {
- while (prev->next != pos)
- {
- prev = prev->next;
- }
- prev->next = pos->next;
- free(pos);
- pos = NULL;
- }
-
- }
思路就是把要删除位置的前一个(prev)找到,然后吧prev的next改成pos的next,最后释放pos
后续还会有更多细节补充