看完B站《王道考研》单链表有关的函数,自己实现了一遍,没有书,纯自己手动敲,有些函数声明定义不是很规范(主要是写给自己看的^_^)
实现了6个函数:
void PrintLink(ld Head);//打印链表
ld HeadChaFa(ld Head);//头插法创建链表(自己写的时候不会英文,用拼音吧 ̄▽ ̄)
ld WeiChaFa(ld Head);//尾插法创建链表
bool ChaRu1(ld Head, int i, int x);//按序位插入
bool InsertNextNode(ld Head, int x);//按给定结点数字后插(偷偷看了一下视频里的函数名)
bool InsertPriorNode(ld Head, int x);//按给定结点数字前插
/*
单链表的实现
*/
typedef struct LNode* ld;
struct LNode {
int data;
ld next;
};
typedef enum { false,true }bool;
void PrintLink(ld Head);
ld HeadChaFa(ld Head);
ld WeiChaFa(ld Head);
bool ChaRu1(ld Head, int i, int x);
bool InsertNextNode(ld Head, int x);
bool InsertPriorNode(ld Head, int x);
int main() {
ld LHead=NULL; //创建一个头结点LHead
printf("开始创建链表(输入范围为整型,输入-9999退出创建):");
/*
接下来利用头插法创建链表:
LHead = HeadChaFa(LHead);
打印链表
PrintLink(LHead);*/
//接下来利用尾插法创建链表:
LHead = WeiChaFa(LHead);
//接下来实现链表的插入:
/* 1.按输入序号插入
int i,x;
printf("请输入你要插入的第i个位置(输入大于等于1):");
scanf("%d", &i);
printf("你要插入的元素x是:");
scanf("%d", &x);
if (!ChaRu1(LHead, i, x)) {
printf("输入位置有误\n");
}
*/
/* 2.插在给定结点的值的后方 与B站《王道计算机考研》数据结构给定节点不同,我按给定结点里面的数字来,区别在于要从头遍历,下面的“插在给定结点数据的前方”也是同理
int x;
printf("请输入给定结点的data是:");
scanf("%d", &x);
if (!InsertNextNode(LHead, x)) {
printf("数据不存在链表中或者链表为空");
}
*/
/* 3.插在给定结点的值的前方
*/
int x;
printf("请输入给定结点的data是:");
scanf("%d", &x);
if (!InsertPriorNode(LHead, x)) {
printf("数据不存在链表中或者链表为空");
}
//打印链表
PrintLink(LHead);
return 0;
}
ld HeadChaFa(ld Head) {//头插法创建链表
Head = (ld)malloc(sizeof(struct LNode));//创建一个头结点,并指向空
Head->next = NULL;//这一步很关键,因为是用头插法,所以最后一个元素指向的是初始时头结点的next指向的地址
//如果没有指向NULL,那么最后一个元素会指向一篇未知的区域
ld p;//创建一个p指针,指向新创建的结点
int x;
scanf("%d", &x);//输入x判断插入操作
while (x != -9999) {//等于-9999时退出操作
//开始头插操作
p = (ld)malloc(sizeof(struct LNode));
p->data = x;
p->next = Head->next;
Head->next = p;
scanf("%d", &x);//改变循环变量,不然死循环了,疯狂申请内存很可怕的
}
return Head;
}
ld WeiChaFa(ld Head) {//尾插法创建链表
Head = (ld)malloc(sizeof(struct LNode));
Head->next = NULL;
ld p, q;
p = q = NULL;
p = Head;
int x;
scanf("%d", &x);
while (x != -9999) {
q = (ld)malloc(sizeof(struct LNode));
q->data = x;
//q->next =NULL; 可以放在循环结束之后
p->next = q;
p = q;
scanf("%d", &x);
}
p->next = NULL;
return Head;
}
bool ChaRu1(ld Head, int i, int x) {//按位序的插入法
if (i < 1)
return false;
int j = 0;//记录到达i处时刻的数字指针
ld p=NULL;//链表前驱
p = Head;
//先把前驱移动到要插入到的位置的前一个
while (p->next != NULL&&j++<i-1) {
p = p->next;
}
if (p == NULL) //如果输入的i太大,则无法插入
return false;
ld s = (ld)malloc(sizeof(struct LNode));
s->data = x;
s->next = p->next;
p->next = s;
printf("插入成功 ");
return true;
}
bool InsertNextNode(ld Head, int x) {//按指定结点数据的后插操作
ld p = NULL;
p = Head;
int i=0;//指定结点在第几个位置上
while (p->next != NULL && p->data != x) {
p = p->next;
i++;
}
if (p == NULL) //说明链表中不存在指定的数字
return false;
int s;
printf("找到x了,它在第%d个位置上,现在你要插入的数据s是:", i);
scanf("%d", &s);
ld q = (ld)malloc(sizeof(struct LNode));
q->data = s;
q->next = p->next;
p->next = q;
printf("插入成功 ");
return true;
}
bool InsertPriorNode(ld Head, int x) {//按指定结点数据的前插操作
ld p = NULL;
p = Head;
int i = 0;//指定结点在第几个位置上
while (p->next != NULL && p->data != x) {
p = p->next;
i++;
}
if (p == NULL) //说明链表中不存在指定的数字
return false;
int s;
printf("找到x了,它在第%d个位置上,现在你要插入的数据s是:", i);
//前面和插入指定结点后一样,要插在前面可以用用复制的思想:
//将新结点的数据与p所在的结点的数据互换位置即可,这也相当于在给定结点前插入一个新结点
ld q = (ld)malloc(sizeof(struct LNode));
q->data = p->data;//先将p结点的data赋值给新结点的data
scanf("%d", &s);//再输入新的data
p->data = s;
//同样的将新结点链接在p后面,这里的“前插”只是名义上的,底层实现还是“后插” 因为不是双向指针,找不到他的前一个指针的地址了,所以用互换data的方法实现类似的效果
q->next = p->next;
p->next = q;
printf("插入成功 ");
return true;
}
void PrintLink(ld Head) {
ld p;//用p前驱去移动打印链表,而不直接用传来的Head,因为传来的Head会改变外面的头结点指针
p = Head;
printf("链表元素分别是:");
while (p -> next != NULL) {
p = p->next;//一定不要忘了移动指针
printf("%d ", p->data);
}
}
bool InsertPriorNode函数,有个很妙的解法,当p前驱找到输入数据对应结点后,想要前插,其实并不需要真正的前插,和后插一样的操作,加上一点点骚操作:把新插入结点中的data与p结点的data交换一下位置即可实现表观意义上的“前插”(借用王道数据结构的图理解一下)
思路还是很新颖的
bool InsertPriorNode(ld Head, int x) {//按指定结点数据的前插操作
ld p = NULL;
p = Head;
int i = 0;//指定结点在第几个位置上
while (p->next != NULL && p->data != x) {
p = p->next;
i++;
}
if (p == NULL) //说明链表中不存在指定的数字
return false;
int s;
printf("找到x了,它在第%d个位置上,现在你要插入的数据s是:", i);
//前面和插入指定结点后一样,要插在前面可以用用复制的思想:
//将新结点的数据与p所在的结点的数据互换位置即可,这也相当于在给定结点前插入一个新结点
ld q = (ld)malloc(sizeof(struct LNode));
q->data = p->data;//先将p结点的data赋值给新结点的data
scanf("%d", &s);//再输入新的data
p->data = s;
//同样的将新结点链接在p后面,这里的“前插”只是名义上的,底层实现还是“后插” 因为不是双向指针,找不到他的前一个指针的地址了,所以用互换data的方法实现类似的效果
q->next = p->next;
p->next = q;
printf("插入成功 ");
return true;
}
还有,我用的是C语言环境下实现,C语言里没有直接的bool类型,要么调包(但是忘了是哪个包的话就......)还有一种就是利用枚举常量enum(刚好可以复习一下enum)
typedef enum { false,true }bool;
还有删除和查找没实现,改天再说吧