数据结构之链表2

实现链表的头插

test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define _CRT_SECURE_NO_WARNINGS 1
#include"slist.h"
//链表的概念及结构
//链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑结构是通过链表中的指针来链接


void testslist()
{
slistnode*plist = NULL;//一开始定义一个指针,但啥都没有,所以先赋值空指针,作为头节点,存入第一个节点的地址
slistpushback(&plist, 1);//尾插//也要传地址才可以,实参传给形参,形参是实参的临时拷贝
slistpushback(&plist, 2);
slistpushback(&plist, 3);
slistpushback(&plist, 4);
slistpushfront(&plist, 0);//头插
slistpopback(&plist);
slistpopfront(&plist);//头删
slistprint(plist);
}
int main()
{
//需要定义一个指针指向头部
testslist();

return 0;
}

slist.c 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#define _CRT_SECURE_NO_WARNINGS 1
#include"slist.h"


void slistprint(slistnode*phead)
{
slistnode*cur = phead;
while (cur != NULL)//遍历是cur不等于空就往下走,走到尾部还不等于空,走到下一个节点,是空的
{
printf("%d->", cur->date);
cur = cur->next;//cur指向下一个指针
}
printf("NULL\n");
}


//开辟节点做的事情很多次,所以直接用一个函数去做开辟节点的事情就可以了

slistnode*buynode(slistdate x)
{
slistnode*newnode = (slistnode*)malloc(sizeof(slistnode));// 要尾插就要动态开辟一个节点出来
newnode->date = x;//将newnode初始化
newnode->next = NULL;//next赋值为空
return newnode;
}


void slistpushback(slistnode**pphead, slistdate x)
{
slistnode*newnode = buynode(x);
//那么我们这个时候要找尾
//找到尾节点的指针
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
slistnode*tail = *pphead;//我们要让tail走到尾部去,而非走到空
while (tail->next != NULL)
{
tail = tail->next;
}//找到了尾节点,链接新节点
tail->next=newnode;
}
}


void slistpushfront(slistnode**pphead, slistdate x)
{
//头插
//也要malloc出来一个节点
slistnode*newnode = buynode(x);
newnode->next = *pphead;//指向头节点,随后要让phead存第一个节点的地址
*pphead = newnode;//phead存入newnode地址,phead作为头节点,就把newnode当作了头节点
}




//尾删要分3种情况分析
//1.没有节点
//2.一个节点
//3.多个节点
void slistpopback(slistnode**pphead)//尾删
{

//1.想删除就找到那个节点,free掉就可以了,因为都是malloc出来的
//但是,如果将tail找到了那个尾节点,直接free掉,那么前一个节点的指针就会变成野指针,它的指针仍有存在值,但是没有指向的目标,
//因此,我们要找到它的前一个节点,再定义一个prev,作为尾节点找到最后一个节点,他的前一个节点

//1.没有节点,即*pphead没有指向,就直接返回不用删除
if (*pphead == NULL)
{
return;
}
//只有一个节点
else if ((*pphead)->next == NULL)//由于*和->的优先级相同,所以为了不报错,就应该把*pphead用括号包含
{
//直接free掉8
free(*pphead);
*pphead = NULL;//再将*pphead置成空指针,防止它变成野指针
}
//有多个节点
else
{
//先定义tail用来找尾,prev找尾前一个节点
slistnode*tail = *pphead;
slistnode*prev = NULL;//prev置成空指针
//找尾节点
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
//此时prev就是尾节点
free(tail);
prev->next = NULL;
}
}


void slistpopfront(slistnode**pphead)//头删
{
//先保存它下一个指针,next
slistnode*next = (*pphead)->next;//next保存第二个节点的地址,之后将其作为第一个节点
//删除头节点
free(*pphead);
*pphead = next;


}

slist.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef int slistdate;//对int重命名,只会方便把int改成double或其他数据类型

struct slistnode
{
slistdate date;//
struct slistnode*next;//指针地址,指向下一个节点
};
typedef struct slistnode slistnode;//方便写

//可能会改变链表的头指针就传二级指针
void slistpushback(slistnode**pphead, slistdate x);//尾插

void slistpushfront(slistnode**pphead, slistdate x);//头插
//不会改变链表的头指针,就传一级指针
void slistprint(slistnode*phead);

void slistpopback(slistnode**pphead);//尾删
void slistpopfront(slistnode**pphead);//头删

1.头插实现

1
2
3
4
5
6
7
8
void slistpushfront(slistnode**pphead, slistdate x)
{
//头插
//也要malloc出来一个节点
slistnode*newnode = buynode(x);
newnode->next = *pphead;//指向头节点,随后要让phead存第一个节点的地址
*pphead = newnode;//phead存入newnode地址,phead作为头节点,就把newnode当作了头节点
}

2.头删

1
2
3
4
5
6
7
8
9
10
void slistpopfront(slistnode**pphead)//头删
{
//先保存它下一个指针,next
slistnode*next = (*pphead)->next;//next保存第二个节点的地址,之后将其作为第一个节点
//删除头节点
free(*pphead);
*pphead = next;


}

4.尾删

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//尾删要分3种情况分析
//1.没有节点
//2.一个节点
//3.多个节点
void slistpopback(slistnode**pphead)//尾删
{

//1.想删除就找到那个节点,free掉就可以了,因为都是malloc出来的
//但是,如果将tail找到了那个尾节点,直接free掉,那么前一个节点的指针就会变成野指针,它的指针仍有存在值,但是没有指向的目标,
//因此,我们要找到它的前一个节点,再定义一个prev,作为尾节点找到最后一个节点,他的前一个节点

//1.没有节点,即*pphead没有指向,就直接返回不用删除
if (*pphead == NULL)
{
return;
}
//只有一个节点
else if ((*pphead)->next == NULL)//由于*和->的优先级相同,所以为了不报错,就应该把*pphead用括号包含
{
//直接free掉8
free(*pphead);
*pphead = NULL;//再将*pphead置成空指针,防止它变成野指针
}
//有多个节点
else
{
//先定义tail用来找尾,prev找尾前一个节点
slistnode*tail = *pphead;
slistnode*prev = NULL;//prev置成空指针
//找尾节点
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
//此时prev就是尾节点
free(tail);
prev->next = NULL;
}
}

数据结构之链表2
http://example.com/2021/11/03/数据结构之链表2/
作者
Zevin
发布于
2021年11月3日
许可协议