目录
一. 单链表的特点
1.1 解引用拓展 🤖
二. 单链表的操作
2.1不带头节点的操作
2.1.1 打印
2.1.1.1 创建结点
2.1.2 尾插(需要二级指针)
注意形参的值不改变实参:(精髓部分)
2.1.3 头插
2.1.4 尾删
2.1.5 头删
2.1.6 在pos前插入
2.1.7 删除pos位置
一. 单链表的特点
单链表的结点是随机的不是逻辑上相邻即物理上相邻的。用指针指向下一个节点的地址。
1.1 解引用拓展 🤖
解引用有两种,* ->
*p的意思是:是取p所指向内存的值,取多少大小的值,取决于结构体前的数据类型,如int 取四个字节,char取一个字节。
p->的意思是: 结构体用->,取决于->后面是什么值,如果是->val则取data域的值,->next则 取下个结点的地址。相当于(*p).next
二. 单链表的操作
单链表分为带头结点和不带头结点 ☆*: .。. o(≧▽≦)o .。.:*☆
2.1不带头节点的操作
2.1.1 打印
打印不用二级指针的原因是:打印不用改变外部结构体指针,只用遍历打印就好了,当要改变结构体指针就要用二级指针。
void SLTPrint(SLNode* phead)
{
SLNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->val);
cur = cur->next;
}
printf("NULL\n");
}
2.1.1.1 创建结点
SLNode* CreateNode(SLNDataType x)
{
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
return newnode;
}
2.1.2 尾插(需要二级指针)
void SLTPushBack(SLNode** pphead, SLNDataType x)
{
SLNode* newnode = CreateNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
// 找尾
SLNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
注意形参的值不改变实参:(精髓部分)
接下来是很多人都迷迷糊糊搞不懂的地方。
当前函数定义的可以直接修改,不是当前当前函数定义的,无论是外部函数,还是malloc出来的空间,访问时都要用指针去通过地址修改。全局变量可以直接修改。
形参不不能改变实参的,要传实参的地址才能改变形参。
想用形参pphead改变外部指针phead(实参) ,先将实参的地址&plist,传给实参pphead,这时pphead代表的是plist地址(&plist),*pphead解引用所以*pphead代表是plist,这里是要改变SNode*,所以要node**。这里是要修改结构体的指针plist,所以是需要结构体指针的地址&plist传给*pphead。
如果要改变外部定义的结构指针SLNode*,要用二级指针SLNode**。
如果要改变外部定义的结构体Node,就要一级指针Node*。
2.1.3 头插
void SLTPushFront(SLNode** pphead, SLNDataType x)
{
SLNode* newnode = CreateNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
2.1.4 尾删
删后n-1个不需要二级指针,直接free();
但是只有一个空间的时候,删掉,plist就成了没有指向空间的野指针,所以需要将plist置空,需要改变结构体指针。
void SLTPopBack(SLNode** pphead)
{
// 温柔的检查
//if (*pphead == NULL)
// return;
// 空
assert(*pphead);
// 1、一个节点
// 2、一个以上节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
// 找尾
/*SLNode* prev = NULL;
SLNode* tail = *pphead;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
prev->next = NULL;*/
SLNode* tail = *pphead;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
2.1.5 头删
void SLPopFront(SLNode** pphead) {
assert(pphead);
if ((*pphead)== NULL) {
free(*pphead);
*pphead= NULL;
}
else {
/**pphead = (*pphead)->next;
free(*pphead);*/
SLNode* tmp = *pphead;
*pphead = (*pphead)->next;
free(tmp);
}
}
2.1.6 在pos前插入
2.1.7 删除pos位置
不带头结点的完整代码
//头文件SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef int SLDataType;
typedef struct SListNode {
SLDataType val;
struct SListNode* next;
}SLNode;
void SLPrint(SLNode* phead);
void SLPushBack(SLNode** pphead, SLDataType x);
void SLPopBack(SLNode** pphead);
void SLPushFront(SLNode** pphead, SLDataType x);
void SLPopFront(SLNode** pphead);
//SList.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include"SList.h"
#include<assert.h>
//打印
void SLPrint(SLNode* phead) {
assert(phead);
while (phead!= NULL) {
printf("%d->", phead->val);
phead = phead->next;
}
printf("NULL\n");
}
//创建新节点
SLNode* CreateNode(SLDataType x) {
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
while (newnode == NULL) {
perror("malloc fail");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
return newnode;
}
//尾插
void SLPushBack(SLNode** pphead, SLDataType x) {
SLNode* newnode = CreateNode(x); //调用函数,实参没有数据类型
if (*pphead == NULL) {
*pphead = newnode;
}
else {
SLNode* tail = *pphead;
while (tail->next != NULL) {
tail = tail->next;
}
newnode->next = NULL;
tail->next = newnode;
}
}
//尾删
void SLPopBack(SLNode** pphead) {
assert(*pphead);
if ((*pphead)->next == NULL) {
free(*pphead);
*pphead = NULL;
}
else {
SLNode* pre = NULL;
SLNode* tail = *pphead;
while (tail->next != NULL) {
pre = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
pre->next = NULL;
}
}
//头插
void SLPushFront(SLNode** pphead, SLDataType x) {
SLNode* newnode = CreateNode(x);
/*if (*pphead == NULL) {
*pphead = newnode;
}*/ //可以不要
newnode->next = *pphead;
*pphead= newnode;
}
//头删
void SLPopFront(SLNode** pphead) {
assert(pphead);
if ((*pphead)== NULL) {
free(*pphead);
*pphead= NULL;
}
else {
/**pphead = (*pphead)->next;
free(*pphead);*/
SLNode* tmp = *pphead;
*pphead = (*pphead)->next;
free(tmp);
}
}
//Test.c 文件
#define _CRT_SECURE_NO_WARNINGS
#include"SList.h"
void Test1() {
SLNode* splist=NULL;
SLPushBack(&splist, 1);
SLPushBack(&splist, 2);
SLPushBack(&splist, 3);
SLPushBack(&splist, 4);
SLPrint(splist);
SLPopBack(&splist);
SLPopBack(&splist);
SLPrint(splist);
SLPushFront(&splist, 1);
SLPushFront(&splist, 2);
SLPushFront(&splist, 3);
SLPushFront(&splist, 4);
SLPrint(splist);
SLPopFront(&splist);
SLPopFront(&splist);
SLPrint(splist);
}
int main() {
Test1();
return 0;
}