1.头文件
#include<stdio.h>
#include<stdlib.h> //针对 malloc and free 的函数
#include <stdbool.h> //针对与true and false 的头文件
注:如果将true 和 false 改为 1 和 0,就不需要#include<stdbool.h>;
2.声明
有很对不同的写法,这里为大家提供了【两种】作为参考,这里来解释以下:
1.定义结构体,由于链表结点是由两部分组成,参数(data)以及指针(node),/*当然这个变量是自己定义的*/ ;
2.定义一个指针Link ,表示 struct node* ;
3.定义一个变量Node, 表示 struct node ;
/*为什么要定义Link 和 Node , 个人认为是为了接下来代码的书写,至少不用每次都来 struct node,看着也别扭;*/
/*定义指针,一部少分是为了方便书写。还有一部分,像头节点一些重要的结点不能丢失,重新定义新的结点来移动还有一大部分是为了起指路灯,方便查找;*/
//单链表节点结构 (习惯使用)
typedef struct node{
int data; //数据域
struct node* next; //指针域
}Node,*Link;
struct Node;
typedef struct Node* PNode;
struct Node {
int info;
PNode link;
};
typedef struct Node* LinkList;
3.创建一个空链表
链表中最后一个元素都要指定为空(NULL),在创建链表的时候一定不能忘记,在【单链表中循环结束的条件一般都是指针指向NULL】;
注:循环链表中循环结束的条件一般都是指针指向头结点(head),这也就是循环链表和单链表的差别,在创建链表时将NULL换成head指针就可以了,平时留心注意一下就可以;
这里有两种创建链表方式,其实说白了也就一种,他们的差别就在与:
第一种只创建了个头指针,插入链表for循环写在了main函数里面,可以查看下面的main函数;
第二种引用函数就可以创建完整的链表;
区别:第一种 + for循环 = 第二种;
-----------------------------------------------------------第一种------------------------------------------------------------
//创建一个空链表
Link creatNullList_Link(void) {
Link llist = (Link)malloc(sizeof(Node)); //给头结点赋予空间
if (llist != NULL) {
llist->next = NULL; //头结点的指针指向空(NULL)
} //链表中最后一个元素都要指定为空
else {
printf("Out of space");
}
return llist; //返回头结点
}
-----------------------------------------------------------第二种------------------------------------------------------------
//创建一个单链表——头插法(数组反序)
Link newList_first(int a[], int n) {
//创建头结点
Link head = (Link)malloc(sizeof(Node));
head->next = NULL;
//创建后续结点
for (int i = 0; i < n; i++) { //for循环将数组的元素插入链表
Link node = (Link)malloc(sizeof(Node));
node->data = a[i];
node->next = head->next;
head->next = node;
}
return head;
}
//创建一个单链表——尾插法(数组正序)
Link newList_post(int a[], int n) {
Link head = (Link)malloc(sizeof(Node));
head->next = NULL;
Link rear = head;
for (int i = 0; i < n; i++) {
Link node = (Link)malloc(sizeof(Node));
node->data = a[i];
node->next = NULL;
rear->next = node;
rear = node;
}
return head;
}
4.打印链表
此方法用于将链表的元素输出;
//单链表遍历操作
void displayNode(Link head) {
Link p = head->next;
while (p != NULL) {
printf("%d", p->data);
p = p->next;
}
}
4.链表结点的个数
//求单链表的元素个数
int length(Link head) {
Link p = head->next;
int count = 0;
while (p != NULL) {
p = p->next;
count++;
}
return count;
}
5.单链表的查找操作
//单链表的查找操作
int queryNode(Link head, int x) {
Link p = head->next; //定义一个新结点用于向后移动
int count = 0;
while (p != NULL) {
if (p->data == x) {
printf("%d",count); //找到则输出下标,
return count; //并提前返回true
}
count++;
p = p->next;
}
//如果循环结束,说明没有找到,返回false
return 0;
}
6.单链表的插入操作
//单链表的插入操作
/*1.工作指针p初始化
* 2.查找第i-1个结点,并使工作指针p指向该结点
* 3.若查找不成功,则返回false
* 否则
* 生成一个元素为x的新节点s
* 将新结点s插入到结点p之后
* 返回true
*/
bool insertNode(Link head, int i, int x) {
Link p = head; //定义一个新结点向后移动(头指针不能移动)
int count = 0;
while (p != NULL && count < i - 1) {
p = p->next;
count++;
}
if (p == NULL) {
return false;
}
else {
Link node = (Link)malloc(sizeof(Node));
node->data = x;
node->next = p->next;
p->next = node;
return true;
}
}
7.单链表结点的删除
//单链表结点的删除(有更新的做法)
/*
1.判断链表是否是空表,如果是空表返回false
2.工作指针p,q初始化
3.若指针p不为空,则继续下列循环
3.1
如果找到数据x所在的p结点,将p结点从链表上摘下
释放p结点
提前返回true,删除成功
否则
3.2
q移动到p所在的位置
p移动到下一个结点
4.循环结束,没有与x相等的结点,返回false
*/
bool deleteNode(Link head, int x) {
if (head == NULL || head->next == NULL) {
return false;
}
Link p, q;
p = head->next;
q = head;
while (p != NULL) {
if (p->data == x) {
q->next = p->next;
free(p);
return true;
}
else {
q = p;
p = p->next;
}
}
//如果循环结束
return false;
}
//单链表结点的删除(不用移动q,比上一个快)
/*1.工作指针p,q初始化
* 2.p为移动结点,从头结点开始
* 3.p 的下一个结点等于 x ,或者为空,停止向后移动(找到x / x不存在链表(最后结点指向NULL))
* 4.在找到x的前提下,将q表示为待删结点
* 5.将q从链表上摘下,释放q
*/
bool deleteNode_1(Link head, int x) {
Link p, q;
p = head;
if (p == NULL) {
return false;
}
while (p->next != NULL && p->next->data != x) {
p = p->next;
}
if (p->next != NULL) {
q = p->next;
p->next = q->next;
free(q);
return true;
}
return false;
}
8.单链表的释放
将链表结点全部释放(包括头指针)
//单链表的释放
void clearLink(Link head) {
Link q;
while (head->next != NULL) {
q = head;
head = head->next;
free(q);
}
}
9.主函数
int main() {
Link head = creatNullList_Link(); //引用函数,创建一个空列表,头指针为head(自定义)
Link rear = head;
printf("请输入插入链表长度:");
int n;
scanf_s("%d", &n);
printf("请输入插入链表的值:");
for (int i = 0; i < n; i++) { //应用了创建链表的第一种(分开写)
int value;
scanf_s("%d", &value);;
Link node = (Link)malloc(sizeof(Node));
node->data = value;
node->next = NULL;
rear->next = node;
rear = node;
}
displayNode(head);
// 插入一个结点
printf("\n");
printf("请输入插入结点位置:");
int i;
scanf_s("%d", &i);
printf("请输入插入结点值:");
int x;
scanf_s("%d", &x);
insertNode(head, i, x);
displayNode(head);
//删除一个结点 (//删除一个值)
printf("\n");
printf("请输入删除结点位置:");
int s;
scanf_s("%d", &s);
deleteNode_1(head, s);
displayNode(head);
//查找一个结点
printf("\n");
printf("请输入查找结点值:");
int v;
scanf_s("%d", &v);
queryNode(head, v);
}
注:由于里面包含很多种方法,小伙伴引用的时候注意以下,主要就是创建空链表部分!!!
10.学习路程
刚开始看书,有些蒙,只理解思路。后来理解了指针怎么淘气之后就可以自己慢慢写代码了,即使错了,也没关系,改呗,哈。
[小愿望]:如果你觉得有帮助的话,点一下下面的小赞赞吧,嘟嘟可会很开心的~