这里创建单链表都是指定长度进行创建的,之后会补上动态创建。
一、头插法创建单链表(p30)
-
由于严蔚敏老师书上的代码是C/C++混着来的,按照书上的代码敲出来的代码,用C语言编译器编译会报错。
-
比如
CreateList_L(LinList &L, int n)
这函数,C语言中是没有引用调用(即 &L) 这种用法的。 -
所以下面给出纯C语言的版本,只需要将 &L 换成指针即可。
-
在这里提出一个
小建议,很多博客写的头插法(包括严蔚敏老师书上的),都用到了typedef struct LNode {} *LinkLIst
,对于新手来说,这种写法不太友好,感觉不太能直观的感受到指针的用法。所以,下面的我直接把它写成了二级指针。 -
之后会补上为什么要这样转化。(即LnikLIst &L -> LNode** L
)==。 -
T(n) = O(n)
-
运行结果
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode* next;
} LNode;
/*
# 头插法创建单链表
- 头插法是将每个节点插入到头节点后面,即如输入1,2,3,4,5
最后的链表应该是 head->5->4->3->2->1
- L是单链表的首地址(头节点)
- n是单链表的节点数目
*/
void List_HeadInsert(LNode** L, int n) {
(*L) = (LNode*)malloc(sizeof(LNode));
(*L)->next = NULL; // 头节点的创建
(*L)->data = n;
// printf("init: %x\n", &L);
for(int i = 0; i < n; i ++) {
LNode* p = (LNode*)malloc(sizeof(LNode));
scanf("%d", &p->data);
p->next = (*L)->next;
(*L)->next = p;
}
}
/*
# 打印单链表
*/
void print(LNode** L) {
// L = L - 40;
// printf("%x\n", &L);
LNode* p = (*L)->next;
if( !p) {
printf("L is NULL.\n");
}
int len = (*L)->data;
printf("Contents of the list are:\n");
for (int i = 0; i < len; i ++) {
printf("%d%s", p->data, i == len - 1 ? "\n" : "->");
p = p->next;
}
}
int main() {
LNode* L;
List_HeadInsert(&L, 5);
// printf("%x\n", &L);
print(&L);
return 0;
}
二、尾插法创建单链表
- 头插法创建的单链表和输入的节点逆序,尾插法则是顺序。
- 代码和运行结果。
- T(n) = O(n)
void List_HeadInsert(LNode** L, int n) {
(*L) = (LNode*)malloc(sizeof(LNode));
(*L)->next = NULL; // 头节点的创建
(*L)->data = n;
// printf("init: %x\n", &L);
for(int i = 0; i < n; i ++) {
LNode* p = (LNode*)malloc(sizeof(LNode));
scanf("%d", &p->data);
p->next = (*L)->next;
(*L)->next = p;
}
}
三、按索引查找和按值查找
- 运行结果和代码。
- T(n) = O(n)
/* 按序号查找节点值 */
LNode* GetElem(LNode** L, int dst) {
if(dst < 0) return NULL;
if(dst == 0) return *L;
LNode* p = (*L)->next;
for (int i = 0 ; i < dst; i ++) {
if(p) p = p->next;
}
return p;
}
/* 按元素值查找结点 */
LNode* LocateElem(LNode** L, int e) {
LNode* p = (*L)->next;
while( p->data != e && p) {
p = p->next;
}
return p;
}
四、插入到第几个节点之后
- 运行结果和代码。
- T(n) = O(n)
/* 插入到第几个节点之后 */
void List_Insert(LNode** L, int dst) {
if(dst < 0) return;
LNode* s = (LNode*)malloc(sizeof(LNode));
printf("var of current insert:\n");
scanf("%d", &s->data);
if(dst == 0) {
s->next = (*L)->next;
(*L)->next = s;
(*L)->data += 1;
return;
}
LNode* p = GetElem(L, dst-1);
s->next = p->next;
p->next = s;
(*L)->data += 1; // 表长加1
}
五、删除节点
- 运行结果和代码。
- T(n) = O(n)
/* 删除第i个节点 */
ElemType List_Delete(LNode** L, int i) {
if(i < 0) return -1;
ElemType res;
LNode *p, *q;
if(i == 0) {
q = (*L)->next;
res = q->data;
(*L)->next = (*L)->next->next;
free(q);
(*L)->data --;
return res;
}
p = GetElem(L, i - 1);
q = p->next;
res = q->data;
p->next = p->next->next;
free(q);
(*L)->data --;
return res;
}