以下是我第一遍写的,成功运行的文件
/**
* 说明:王道版数据结构,LNode *, LinkList两个东西虽然实际表示的东西是一样的,
* 但是LNode *强调这是一个结点的指针,LinkList则表示一个链表(头指针、头结点的指针)
* 其次,王道版链表是带头结点的
*/
#include "stdio.h"
#include "stdlib.h"
#include "stdbool.h"
typedef struct LNode { // 定义单链表结点类型
int data; // 每个结点存放一个数据元素
struct LNode *next; // 指针指向下一个结点
} LNode, *LinkList;
// 初始化一个单链表(带头结点)
LinkList initList(LinkList L) {
L = (LNode *) malloc(sizeof(LNode)); // 分配一个头结点
L->data = 999;//头结点的数据域可以没有,也可以是别的,比如可以是链表长度
if (L == NULL) { // 内存不足,分配失败
printf("L == NULL");
return 0;
}
L->next = NULL; // 头结点之后暂时还没有结点
return L;
}
/**
* 在第i个位置插入元素e(带头结点)
*/
bool ListInsert(LinkList L, int i, int e) {
if (i < 1) {
printf("i < 1");
return 0;
}
LNode *p; // 创建一个当前指向的结点
p = L; // 初始化指向到头结点
int j = 1;
//将p指向某结点,该结点后面要插入新结点
while (j < i) {
p = p->next;
j++;
}
LNode *s; // 新建一个待插入的新节点
s = (LNode *) malloc(sizeof(LNode)); // 给新节点分配内存
s->data = e; // 给新节点放入数据
s->next = p->next; // 新节点指向当前结点的下一个结点
p->next = s; // 原结点指针改为指向到新创建的结点
}
void readAll(LinkList L) {
LNode *p;
p = L;
while (p->next != NULL) {
p = p->next;
printf("%d \n", p->data);
}
}
void deleteItem(LinkList L, int i) {
int j;
LNode *s;
s = L;
for (j = 0; j < i - 1; j++) {
s = s->next;
}
LNode *t = s->next;
s->next = s->next->next;
free(t);
}
int main() {
LinkList L;
// LNode L;
L = initList(L);
ListInsert(L, 1, 111);
ListInsert(L, 1, 222);
ListInsert(L, 1, 333);
printf("三次插入后的结果\n");
readAll(L);
printf("删除后的结果\n");
deleteItem(L, 2);
readAll(L);
return 0;
}
注意到王道书上有一个细节,在需要更改链表本身的时候,在参数列表里会增加一个取地址符,但是我加上之后编译器反而报错了
还是不明白这里为什么要加取地址符,我们本身传递进去的就是一个指针变量(LinkList),输入指针变量已经是引用传递了吧?
c++才有引用传递,c语言里没有
C++引用,供参考:https://baike.baidu.com/item/C%2B%2B%E5%BC%95%E7%94%A8/463646?fr=aladdin
题主的代码里,将源文件.c 的后缀,重新保存成 .cpp后缀,即可实现,初始化单链表函数可以不需返回值,修改如下,供参考 :
#include "stdio.h"
#include "stdlib.h"
//#include "stdbool.h"
typedef struct LNode { // 定义单链表结点类型
int data; // 每个结点存放一个数据元素
struct LNode *next; // 指针指向下一个结点
} LNode, *LinkList;
// 初始化一个单链表(带头结点)
void initList(LinkList& L) { //修改 LinkList initList(LinkList& L)
L = (LNode *) malloc(sizeof(LNode)); // 分配一个头结点
L->data = 999;//头结点的数据域可以没有,也可以是别的,比如可以是链表长度
if (L == NULL) { // 内存不足,分配失败
printf("L == NULL");
return; //return 0; //修改
}
L->next = NULL; // 头结点之后暂时还没有结点
//return L; //修改
}
/**
* 在第i个位置插入元素e(带头结点)
*/
bool ListInsert(LinkList L, int i, int e) {
if (i < 1) {
printf("i < 1");
return 0;
}
LNode *p; // 创建一个当前指向的结点
p = L; // 初始化指向到头结点
int j = 1;
//将p指向某结点,该结点后面要插入新结点
while (j < i) {
p = p->next;
j++;
}
LNode *s; // 新建一个待插入的新节点
s = (LNode *) malloc(sizeof(LNode)); // 给新节点分配内存
s->data = e; // 给新节点放入数据
s->next = p->next; // 新节点指向当前结点的下一个结点
p->next = s; // 原结点指针改为指向到新创建的结点
}
void readAll(LinkList L) {
LNode *p;
p = L;
while (p->next != NULL) {
p = p->next;
printf("%d \n", p->data);
}
}
void deleteItem(LinkList L, int i) {
int j;
LNode *s;
s = L;
for (j = 0; j < i - 1; j++) {
s = s->next;
}
LNode *t = s->next;
s->next = s->next->next;
free(t);
}
int main() {
LinkList L;
//LNode L;
//L = //修改
initList(L); //修改
ListInsert(L, 1, 111);
ListInsert(L, 1, 222);
ListInsert(L, 1, 333);
printf("三次插入后的结果\n");
readAll(L);
printf("删除后的结果\n");
deleteItem(L, 2);
readAll(L);
return 0;
}
王道书上是伪代码,建议买上机的书边敲边练,另外一般现在上机是用的c++,引用在中是没有的,指针和引用不能混为一谈,可以搜索指针和引用的区别,例如引用不会导致断链而指针可能导致,这涉及底层的内存调用。