一、链表的基本概念
通俗的来说,链表就是一列火车,车厢就是节点。
车厢通过挂钩来链接,而链表通过节点的指针域链接。
车厢包括货物和链接挂钩,而节点包括数据域(货物)和指针域(挂钩)。
最后一个车厢拥有挂钩,但是不会链接下一个车厢,所以最后一个节点有数据域,而他的指针域指向空(NULL);
代码的实现:
struct Node
{
int data; //数据域
char Name[40]; //数据域
//....... 数据域可以有很多个
struct Node* next; //指针域,只有一个,指向下一个节点
};
二、静态链表
静态链表不常用:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
//车厢构建完毕
int main()
{
struct Node Node1={1,NULL}; //Node1,其数据域里面存放1,指针域为空
struct Node Node2={2,NULL}; //Node2,其数据域里面存放3,指针域为空
struct Node Node3={3,NULL};
//定义好了车厢,接下来要连接车厢
Node1.next=&Node2; //将Node2的地址发送给Node1,完成链接
Node2.next=&Node3; //将Node3的地址发送给Node2,完成链
//Node3最为最后一个指针,没有指向的地址。
printf("%d %d %d\n",Node1.data,Node1.next->data,Node1.next->next->data);
return 0;
}
通过 Node1 的地址,将Node2、Node3的地址先赋予好,再将Node2、Node3的值全部打印出来,但是如果在这个基础上继续增加,那么就需要不停的去赋值,很麻烦,所以这种静态链表,基本不用。
三、动态链表
这种链表在初始时不一定分配足够的空间, 但是在后续插入的时候需要动态申请存储空间,并且存储空间不一定连续, 在进行插入和删除时则不需要移动元素, 修改指针域即可,所以仍然具有链表的主要优点,链表结构可以是动态地分配存储的,即在需要时才开辟结点的存储空间,实现动态链接。
3.1 动态链表步骤
1)创建火车头(创建一个链表)
2)创建车厢(创建节点)
3)增加车厢(增加节点)
4)删除车厢(删除节点)
3.2 代码实现
struct Student *Number
{
struct Student *Head = (struct Student *)malloc(sizeof(struct Student));
//动态申请空间
Head->Next = NULL;
return Head;
}
//火车头定义完毕
struct Student *Number(int data)
{
struct Student *New = (struct Student *)malloc(sizeof(struct Student));
New->data = data;
New->Next = NULL;
}
//车厢简历完毕,与车头相比车厢多了货物,也就是数据域
增加车厢
/*1)尾插法
最后一个结点的指针域始终指向空,所以我们要新增一个结点只需要把之前最后一个结点的指针指向新结点的地址,新结点的指针指向空就好了*/
void Add(struct Student *Head)
{
struct Student *New = (struct Student *)malloc(sizeof(struct Student));
if(Head == NULL)
{
printf("这是一个空链表\n");
}else
{
Head->Next = New;
New->Next = NULL;
}
}
/*2)头插法
新增加的结点的指针域指向之前的头结点就好;把现在的结点变为头结点*/
void Add(struct Student *Head)
{
struct Student *New = (struct Student *)malloc(sizeof(struct Student));
if(Head == NULL)
{
printf("这是一个空链表\n");
}else
{
New->Next = Head;
Head = New;
}
}
/*3)中间插入
找到你要插入的结点,将它的指针域指向新节点的数据域,再把新节点的数据域指向原来下一个结点的指针域*/
void Add(struct Student *Head,int data)
{
struct Student *New = (struct Student *)malloc(sizeof(struct Student));
while(Head->Next != NULL)
if(Head->Next->data == data)//找到对应的结点
{
New = Head->Next;
New->Next = Head->Next->Next;
}
Head = Head->Next;//遍历链表找对应的结点
}
删除车厢
/*1)删除头结点
把原来的头结点去掉,将下一个结点作为一个新的结点*/
void Delete(struct Student *Head,int data)
{
if(Head->data == data)//删除的结点刚好是头结点
{
Head = Head->Next;
return Head;
}
}
/*2)删除中间点
遍历链表的时候删除终中间的结点就可以*/
void Delete(struct Student *Head,int data)
{
while(Head->Next != NULL)
{
if(Head->Next->data == data)
{
Head->Next = Head->Next->Next;
return Head;
}
Head = Head->Next;
}
}
四、结构体的定义
举个例子:
结构体就是一个班级,结构体名字就是几年级几班。班级肯定是用来给学生上课的嘛,学生就是各种指针。
对结构体的使用就是直接叫那个班的某某学生的名字就好了。
//定义一个结构体,结构体是用来表示学生的
struct Student
{
int Age;
char Name[20];
int Xuehao;
double Math;
double English;
//指针就是学生的各种属性,年龄、名字、学号、成绩等
};
//这个冒号一定要记得!!!这是结构体的标志