前言吐槽
今日学习内容是C语言的单链表,本人真的是被C逼疯了,此话怎讲呢?本人学校内开的课程里有C语言,但是······我感觉我对C的感觉就跟看汇编一样,没兴趣···倒不是看不懂程序,毕竟我还会点C#,但糟心就糟心在在学习C的时候,我遇见了一个“神奇”的老师,她有个爱好叫做——“照着书打字呀,好好看着书打呀。”
比如你写程序书上是%d,你就必须是%d,不然她就说你不会打字,啧,我又不是学打字的【摊手】
编写C语言的链表
C的难度蛮大的,很多东西我们需要自己去申明,像我昨天写的Java程序那叫一个舒爽,别的都不管,做个链表也不用自己去做一个数据域,但是C语言需要
这里做一个小笔记
C语言是个很自由的编程语言,所以很多知识不知道的话,是没有思路写下去的,因为它过分自由了,导致编写它有相当严格的知识储备要求,如果做不到这些储备的,就和我一样找个c语言代码看着,如果有其他语言的底子,看懂大概意思是不成问题的。
所以我一直秉持一个态度:程序没思路,先去看看别人的思路,不会就照着打直到打字打懂
上程序了
PNode CreateList(void)
{
int len; // 用于定义链表的长
int val; // 用于存放节点数值
PNode PHead = (PNode)malloc(sizeof(Node)); // 创建分配一个头节点内存空间
if (PHead == NULL) // 判断是否分配成功
{
printf("空间分配失败 \n");
exit(-1);
}
PNode PTail = PHead; // 链表的末尾节点,初始指向头节点
PTail->Next = NULL; // 最后一个节点指针置为空
printf("请输入节点个数:");
scanf_s("%d", &len); // 输入节点个数
for (int i = 0; i < len; i++)
{
PNode PNew = (PNode)malloc(sizeof(Node)); // 分配一个新节点
if (PNew == NULL)
{
printf("分配新节点失败\n");
exit(-1);
}
printf("请输入第 %d 个节点的数据:", i + 1);
scanf_s("%d", &val); // 输入链表节点的数据
PNew->Element = val; // 把数据赋值给节点数据域
PTail->Next = PNew; // 末尾节点指针指向下一个新节点
PNew->Next = NULL; // 新节点指针指向为空
PTail = PNew; // 将新节点复制给末尾节点
}
printf("创建链表成功\n");
return PHead; // 返回头节点
}
对比Java的创建
我感觉真的差的不是一丁半点啊,各位可以对比一下看看
public class Mylink {
Node head = null; // 使用給定值初始化新節點node
public static final int Subscript= 1;
class Node {
Node next = null;// 將cur的next的字段链接到下一个结点
int val;//定义一个值,作为节点内容
public Node(int data) {
this.val = data;
}
}
删除数据
跟大家上程序来感受一下,Java、和c语言的魅力
先是Java
public boolean deleteNode(int index) {
if (index < 1 || index > length()) {
System.out.println("删除错误");
return false;
}
if (index == 1) {
head = head.next;
System.out.println("删除成功!");
return true;
}
int i = 1;
Node preNode = head;
Node curNode = preNode.next;
while (curNode != null) {
if (i == index) {
preNode.next = curNode.next;
return true;
}
preNode = curNode;
curNode = curNode.next;
i++;
}
return false;
}
再来c语言
void DeleteList(PNode List, int pos) {
int position = 0;
PNode P = List; // 定义一个指针p指向链表头节点
// 寻找pos节点位置的前驱节点
while (P != NULL && position < pos - 1) {
P = P->Next;
++position;
}
// 删除节点
PNode Tmp = P->Next; // 定义临时指针Tmp指向要删除的节点
P->Next = Tmp->Next; // 使要删除节点的前驱结点指向其后驱节点
free(Tmp); // 释放删除节点的内存空间,防止内存泄漏
Tmp = NULL; // 使q指向空指针,防止产生野指针
}
看到现在,我脑阔疼,为什么会有c语言这么自由自在的语言呢?很多在Java,C#,python中可以直接用的东西,但在C里你就学会踏踏实实的做人,专门克制那些花里胡哨的骚操作···
接下来就不废话了,直接看程序吧,这个注释应该是可以看的,看不看得懂看大家的造化了
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef int ElementType; // 定义数据类型,可根据需要进行其他类型定义
// 链表节点的定义
typedef struct ListNode
{
ElementType Element; // 数据域,存放数据
ListNode* Next; // 指向下一个链表节点
}
Node, * PNode;
// --------------- 函数声明 ------------------
PNode CreateList(void); // 声明创建链表函数
void TraverseList(PNode List); // 声明遍历链表函数
void InsertlinkList(PNode List, int pos, int val); // 声明链表插入函数
void DeleteTheList(PNode List); // 声明删除整个链表函数
void DeleteList(PNode List, int pos); // 声明删除链表元素函数
PNode FindList(PNode List); // 声明链表查询函数
/*------------------ 主函数 ---------------*/
int main() {
PNode List = CreateList(); // 创建一个指针,使其指向新创建的链表的头指针
TraverseList(List
); // 遍历链表
FindList(List); // 链表查询
InsertlinkList(List, 3, 100); // 链表插入,在第三个位置插入数值100
TraverseList(List);
DeleteList(List, 3); // 删除链表第三个节点
TraverseList(List);
DeleteTheList(List); // 删除整个链表
TraverseList(List);
return 0;
}
/*--------------------------
*NAME:CreateList
*作用:创建链表函数定义
*--------------------------
*/
PNode CreateList(void)
{
int len; // 用于定义链表长度
int val; // 用于存放节点数值
PNode PHead = (PNode)malloc(sizeof(Node)); // 创建分配一个头节点内存空间
if (PHead == NULL) // 判断是否分配成功
{
printf("空间分配失败 \n");
exit(-1);
}
PNode PTail = PHead; // 链表的末尾节点,初始指向头节点
PTail->Next = NULL; // 最后一个节点指针置为空
printf("请输入节点个数:");
scanf_s("%d", &len); // 输入节点个数
for (int i = 0; i < len; i++)
{
PNode PNew = (PNode)malloc(sizeof(Node)); // 分配一个新节点
if (PNew == NULL)
{
printf("分配新节点失败\n");
exit(-1);
}
printf("请输入第 %d 个节点的数据:", i + 1);
scanf_s("%d", &val); // 输入链表节点的数据
PNew->Element = val; // 把数据赋值给节点数据域
PTail->Next = PNew; // 末尾节点指针指向下一个新节点
PNew->Next = NULL; // 新节点指针指向为空
PTail = PNew; // 将新节点复制给末尾节点
}
printf("创建链表成功\n");
return PHead; // 返回头节点
}
/*--------------------------
*NAME:TraverseList
*作用:定义链表遍历函数
*参数:PNode List
*--------------------------
*/
void TraverseList(PNode List)
{
PNode P = List->Next; // 首节点赋值给临时节点P
printf("遍历链表的值为:");
if (P == NULL)
printf("链表为空");
while (P != NULL) //当临时节点P不为尾节点时,输出当前节点值
{
printf("%d ", P->Element);
P = P->Next;
}
printf("\n");
}
/*-------------------------
*NAME:FindList
*作用:定义链表查询函数
*参数:PNode List
*-------------------------
*/
PNode FindList(PNode List)
{
PNode P = List->Next; // 定义临时指针P指向首节点的地址
int num = 0; // 用于记录链表节点位置
int val = 0; // 用于存放要查询的值
printf("请输入要查询的数:");
scanf_s("%d", &val); // 输入要查询的数值
while (P != NULL && P->Element != val)
{
P = P->Next;
++num;
}
if (P != NULL)
printf("找到的节点为:%d", num + 1);
else
printf("找不到该节点");
printf("\n");
return P;
}
/*------------------------------------------------------
*NAME:InsertList
* 作用:定义链表插入函数
* 操作:在链表位置第pos节点前插入包含数据val的节点
* 参数:PNode List, int pos, int val
*------------------------------------------------------
*/
void InsertlinkList(PNode List, int pos, int val) {
int position = 0;
PNode P = List; // 定义节点p指向头节点
// 寻找pos节点的前驱结点
while (P != NULL && position < pos - 1)
{
P = P->Next;
++position;
}
PNode Tmp = (PNode)malloc(sizeof(Node)); // 分配一个临时节点用来存储要插入的数据
if (Tmp == NULL)
{
printf("内存分配失败!");
exit(-1);
}
// 插入节点
Tmp->Element = val;
Tmp->Next = P->Next;
P->Next = Tmp;
}
/*--------------------------------
*NAME: DeleteTheList
*作用:定义删除整个链表函数
*参数:PNode List
*--------------------------------
*/
void DeleteTheList(PNode List)
{
PNode P, Tmp;
P = List->Next; //定义指针P指向链表要删除的链表List的第一个点节点
List->Next = NULL;
while (P != NULL)
{
Tmp = P->Next; //临时Tmp指向要删除的节点的下个节点
free(P); //释放指针P指向的节点
P = Tmp; //重新赋值
}
printf("删除链表成功!\n");
}
/*------------------------------------------------
*NAME: DeleteList
*作用:定义删除链表元素函数,删除链表中的第pos节点
*参数:PNode List, int pos
*------------------------------------------------
*/
void DeleteList(PNode List, int pos) {
int position = 0;
PNode P = List; // 定义一个指针p指向链表头节点
// 寻找pos节点位置的前驱节点
while (P != NULL && position < pos - 1) {
P = P->Next;
++position;
}
// 删除节点
PNode Tmp = P->Next; // 定义临时指针Tmp指向要删除的节点
P->Next = Tmp->Next; // 使要删除节点的前驱结点指向其后驱节点
free(Tmp); // 释放删除节点的内存空间,防止内存泄漏
Tmp = NULL; // 使q指向空指针,防止产生野指针
}