线性表之单链表

单链表概述

一张图简单解释下单链表的结果,对头节点,头指针,首节点混肴的同学可以再看看
这里写图片描述

以下是单链表的头文件和相关操作,这门课很抽象,我个人认为只在脑海中去理解很难做到,因为指针指来指去是个人都会晕,建议大家用笔在纸上画出来,更容易理解
比如单链表的尾插法, 在纸上一画瞬间理解了

代码实现

linklist.h如下:

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <malloc.h>

typedef int ElemType;
typedef struct Node{
ElemType data;
struct Node *next;
}LinkList;

LinkList.cpp如下:

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include "linklist.h"
#include <stddef.h>

void headInit(LinkList * &ls, int msg[], int n);//头插法
void tailInit(LinkList * &ls, int msg[], int n);//尾插法
void printLinkList(LinkList *ls);//输出链表
void destory(LinkList *&ls);//销毁链表
int getLength(LinkList *ls);//获取长度
bool getElementByIndex(LinkList *ls, int pos, ElemType &e);//通过下标获取元素
int getElementIndex(LinkList *ls,ElemType e);//获取元素的下标
bool insert(LinkList *&ls,int pos, ElemType e);
bool deleteElement(LinkList *&ls, int pos, ElemType &e);

/**
* 相比于顺序表,单链表不需要连续的空间,没有冗余的空间,而且不用扩容,插入和删除操作效率高
* 但是其他操作复杂
*/
int main()
{
LinkList * ls;

ElemType arr1[] = {1,2,3,4,5};
headInit(ls,arr1,5);
printLinkList(ls);

ElemType arr2[] = {6,7,8,9,10};
tailInit(ls,arr2,5);
printLinkList(ls);

printf("\n单链表的长度是:%d\n",getLength(ls));

ElemType e;
if(getElementByIndex(ls,5,e)){
printf("第%d个元素的值是:%d\n",5,e);
}

int pos = getElementIndex(ls,10);
if(pos){
printf("%d的位置是:%d\n",10,pos);
}

e = 11;
if(insert(ls,6,11)){
printf("%d插入成功\n",e);
}
printLinkList(ls);

if(deleteElement(ls,5,e)){
printf("\n要删除的第%d个元素是%d,已删除成功\n",5,e);
}
printLinkList(ls);
destory(ls);
return 0;
}

/*
头插法
*/
void headInit(LinkList * &ls, ElemType msg[], int n) {
int i;
LinkList *node;
ls = (LinkList*)malloc(sizeof(LinkList));
ls->next = NULL;
for (i = 0; i < n; i++){
//产生一个新节点
node = (LinkList*)malloc(sizeof(LinkList));
node->data = msg[i];
//把该节点插到头节点的后面,画图
node->next = ls->next;
ls->next = node;
}
}
/*
尾插法:定义一个尾指针指向尾节点,因为每次都在尾节点后面插,就把尾节点当作头节点去插
*/
void tailInit(LinkList * &ls, int msg[], int n) {
ls = (LinkList*)malloc(sizeof(LinkList));
ls->next = NULL;
int i;
LinkList *node,*tail = ls; //尾指针最初也指向头节点
for (i = 0; i < n; i++){
node = (LinkList*)malloc(sizeof(LinkList));
node->data = msg[i];
tail->next = node;
tail = node; //尾指针指向新插入的节点,即尾节点
}
//一开始没加这句,导致tail->next成为野指针,导致一直输出
tail->next = NULL;
}

//打印
void printLinkList(LinkList *ls) {
LinkList *p = ls->next;
while (p != NULL) {
printf("%d\t", p->data);
p = p->next;
}
}

/**
* 链表的消耗要把每一个节点都free
*/
void destory(LinkList *&ls){
LinkList * head = ls, * p = ls->next;
while(p!=NULL){
free(head);
head = p;
p = p->next;
}
//销毁最后一个
free(head);
}

//判断是否是空表
bool isEmpty(LinkList *ls){
return (ls->next == NULL);
}

//求表长
int getLength(LinkList *ls){
LinkList * p = ls;
int i = 0;
while(p->next != NULL){
i++;
p = p->next;
}
return i;
}

//获取第i个节点
bool getElementByIndex(LinkList *ls, int pos, ElemType &e){
int i = 0;
LinkList * p = ls;
while(i<pos && p!=NULL){
p = p->next;
i++;
}
//循环结束后要么i<pos不成立,也就是找到了,要么ls==NULL,也就是到表尾了
if(p == NULL){
printf("不存在第%d个元素\n",pos);
return false;
}else{
e = p->data;
return true;
}
}

//获取元素下标
int getElementIndex(LinkList *ls,ElemType e){
//用pos记录下标
int pos = 1;
LinkList *p = ls->next;
while(p != NULL && p->data != e){
p = p->next;
pos++;
}
//对循环结束后的条件进行判断
if(p == NULL){
return 0;
}else{
return pos;
}
}

/**
* 单链表的插入需要记录前一个节点,所以找到pos-1即可
*/
bool insert(LinkList *&ls,int pos, ElemType e){
int i = 0;
LinkList * p = ls; //不要直接用ls
//pos-1,假如在第5个位置插入,就找出第四个节点,让它指向e
while(i < pos-1 && p != NULL){
i++;
p = p->next;
}
if(p==NULL){
return false;
}else{
//为插入的节点分配空间
LinkList * node = (LinkList *) malloc (sizeof(LinkList));
node->data = e;

//插入
node->next = p->next;
p->next = node;
return true;
}
}

//删除同样也要找到pos-1个节点
bool deleteElement(LinkList *&ls, int pos, ElemType &e){
int i = 0;
LinkList * p = ls , *temp;
while(i < pos-1 && p!=NULL){
p = p->next;
i++;
}
if(p==NULL){
return false;
}else{
//删除节点,记得先把地址用temp保存起来,用于free
temp = p->next;
e = temp->data;
p->next = temp->next;
free(temp);
return true;
}
}

输出结果

1
2
3
4
5
6
7
8
5	4	3	2	1	6	7	8	9	10	
单链表的长度是:5
第5个元素的值是:10
10的位置是:5
11插入成功
6 7 8 9 10 11
要删除的第5个元素是10,已删除成功
6 7 8 9 11
Author: 紫夜
Link: https://greedypirate.github.io/2017/07/10/线性表之单链表/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
支付宝打赏
微信打赏