【单链表】
单链表
- 1. 函数的声明部分
- 2. 函数的实现部分
-
- (1)打印链表
- (2)头插
- (3)尾插
- (3)头删
- (4)尾删
- (5)单链表的查找
- (6)删除pos位置之后的值
- (7)在pos位置之后插入x
- 3. 函数的测试部分
单链表概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
1. 函数的声明部分
#pragma once#include <stdio.h>#include <stdlib.h>#include <assert.h>typedef int SLTDateType;typedef struct SingleListNode{SLTDateType data;struct SingleListNode* next;}SLTNode;//打印void SLTPrint(SLTNode* phead);//头插void SLTPushFront(SLTNode pphead, SLTDateType x);//尾插void SLTPushBack(SLTNode pphead, SLTDateType x);//头删void SLTPopFront(SLTNode pphead);//尾删void SLTPopBack(SLTNode pphead);//在pos位置之后插入xvoid SLTInsertAfter(SLTNode* pos, SLTDateType x);//删除pos位置之后的值void SLTEraseAfter(SLTNode* pos);//单链表查找SLTNode* SLTFind(SLTNode pphead, SLTDateType x);
2. 函数的实现部分
由于头插,尾插等需要开辟一个节点,所以把开辟节点单独作为一个函数,需要开辟节点的时候直接调用;
SLTNode* BuyListNode(SLTDateType x){//开辟一个节点SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));assert(newnode);//对newnode初始化newnode->data = x;newnode->next = NULL;return newnode;}
(1)打印链表
//打印void SLTPrint(SLTNode* phead){SLTNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;}printf("NULL\\n");}
(2)头插
头插需要传二级指针,因为在调用函数SLTPushFront的时候,实参plist本来是结构体指针,现在头插需要改变链表的头,即需要传地址去改变plist的头;
如进行以下操作,值传递操作:
假设链表是如下形式:
当头插函数使用一级指针接收实参时,实参和形参同为一级指针,它们是同等类型的,它们在两个不同的栈空间,假如进行以下操作:
实际上phead并不会改变plist的值:
因为它们两个在不同的栈空间,phead只是plist的临时拷贝,只要出了SLTPushFront这个函数,栈帧被销毁,phead也被销毁了,但是phead的改变也没有改变plist的值,所以相当于什么也没有发生;
所以需要传二级指针,存放plist的指针,到函数内部需要解引用找到plist,再去改变plist的值,这样才能达到我们想要的效果;
//头插void SLTPushFront(SLTNode pphead, SLTDateType x){SLTNode* newnode = BuyListNode(x);//将newnode的next更新为原来的头节点newnode->next = *pphead;//将newnode更新为新的头节点*pphead = newnode;}
(3)尾插
尾插的时候,当链表为空时,需要改变的是plist这个结构体指针,所以这个时候也是要传二级指针;当链表为非空链表时,需要改变的是结构体,所以不需要用到二级指针;但为了防止链表为空,这里干脆直接传二级指针;
//尾插void SLTPushBack(SLTNode pphead, SLTDateType x){SLTNode* newnode = BuyListNode(x);//空链表if (*pphead == NULL){*pphead = newnode;}//非空链表else{SLTNode* tail = *pphead;while (tail->next){tail = tail->next;}tail->next = newnode;}}
(3)头删
//头删void SLTPopFront(SLTNode pphead){//没有节点assert(*pphead);//一个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}//多个节点else{SLTNode* cur = *pphead;*pphead = cur->next;free(cur);cur = NULL;}}
(4)尾删
//尾删void SLTPopBack(SLTNode pphead){//空链表assert(*pphead);//一个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}//多个节点else{SLTNode* tail = *pphead;while (tail->next->next){tail = tail->next;}free(tail->next);tail->next = NULL;}}
(5)单链表的查找
SLTNode* SLTFind(SLTNode* phead, SLTDateType x){SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next; }return NULL;}
(6)删除pos位置之后的值
void SLTEraseAfter(SLTNode* pos){assert(pos && pos->next);SLTNode* cur = pos;cur->next = cur->next->next;}
(7)在pos位置之后插入x
void SLTInsertAfter(SLTNode* pos, SLTDateType x){SLTNode* cur = BuyListNode(x);assert(cur);cur->next = pos->next;pos->next = cur;}
3. 函数的测试部分
#define _CRT_SECURE_NO_WARNINGS 1#include "Single List.h"int main(){SLTNode* plist = NULL;SLTPushFront(&plist, 2);SLTPushFront(&plist, 1);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 5);//SLTPopFront(&plist);//SLTPopBack(&plist);//SLTInsertAfter(plist->next->next, 10);SLTEraseAfter(plist);SLTPrint(plist);SLTNode* ret = SLTFind(plist, 5);if (ret != NULL){printf("%d->", ret->data);}else{printf("NULL\\n");}SListDestroy(&plist);return 0;}