由于数组空间是连续的,有些时候定义了可能没有完全使用,操作起来麻烦,而链表是需要使用节点时,会动态开辟合理利用碎片化空间。
数组在进行数据的插入,删除操作时,为了保证内存数据的连续性,往往需要做大量的数据搬移工作。而在链表中插入或删除数据时,因为链表结构中的节点并不需要连续的存储空间,所以在链表中进行数据的插入和删除时并不需要搬移节点。对于链表的删除和插入操作,我们只需要调整相邻节点的后继指针即可.
链表由节点组成,节点由数据域(存放的数据)和指针域(下一个节点的地址)组成。节点有头节点,即链表中的第一个节点;尾节点,链表的最后一个节点,指针域为NULL;
1.节点的定义
- 直接定义
struct NODE{
char name[32];
int id;
float score;
struct NODE *addr; //下一个节点的地址
};
定义一个节点类型,其中里面有数组name[32]存放姓名,整型变量id存放学号,浮点型变量score存放成绩,再定义一个指针addr数据类型为struct NODE存放下一个节点的地址;
- 先定义数据域,再定义节点
struct Stu{
char name[32];
int id;
float score;
};
struct NODE{
struct Stu stu; //数据域
struct NODE *addr;//指针域, 下一个节点的地址
}
先把数据域的结构体定义好,然后再定义节点,包含数据域和指针域;更容易读懂,明白要表达的意思,代码的可读性提高。
2.相关函数
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int *p=(int *)malloc(sizeof(int));
if(p==NULL)
{
printf("创建失败\n");
}
memset(p,0,sizeof(int));
*p=100;
printf("*p=%d\n",*p);
free(p);
return 0;
}
①malloc:开辟空间
#include <stdlib.h>
void *malloc(size_t size);
形参: size -->要开辟空间的大小(字节)
返回值:成功,返回开辟好的空间的首地址,void * --> 万能指针,可以随意的强转为你想要的类型;失败,NULL;
例:int *p = (int *)malloc(sizeof(int));
*p = 100;
②free:释放空间
void free(void *ptr);
形参:要释放的空间的首地址;
返回值:void-->无返
③memset:内存清理函数
#include <string.h>
void *memset(void *s, int c, size_t n);
将s中当前位置后面的n个字节用 c替换并返回 s 。
形参: s,你要清理的空间的首地址
c=0
n,清理多大,利用sizeof
返回值:函数的第一个形参
3.双向链表:
节点:数据域和指针域(存放上一个和下一个节点的地址)
struct Stu{
char name[32];
int id;
float score;
};
struct NODE{
struct Stu stu; //数据域
struct NODE *front; //指针域, 上一个节点的地址
struct NODE *next; //指针域, 下一个节点的地址
}
要想添加新的节点,先遍历节点到尾节点,然后让尾节点的next指针域指向新的节点;
struct NODE *tmp=head;
struct NODE *new=(struct NODE *)malloc(sizeof(struct NODE));//创建新的节点new
memset(new,0,sizeof(struct Stu));//数据域清零
new->front=NULL;//指针域为空
new->next=NULL;
//对节点new数据域赋值
printf("请输入学生学号:\n");
scanf("%d",&new->stu.id);
printf("请输入学生姓名:\n");
scanf("%s",new->stu.name);
printf("请输入学生成绩:\n");
scanf("%f",&new->stu.score);
//令tmp等于头节点,对next地址域进行判断
tmp = head;
while(tmp->next!=NULL)
{
tmp=tmp->next;//tmp的next地址域指向下一个节点
}//此时tmp已经来到尾节点
tmp->next=new;//把new的地址传到尾节点的next地址域中
new->front=tmp;
4.循环链表
循环链表是一种特殊的单链表,特殊之处在于,我们在单链表中,尾节点的后继指针或者引用不是指向一个具体的节点,而是指向一个空地址NULL,表示这就是最后一个节点。而将单链表的尾节点从指向空地址NULL调整为指向头结点Head,就形成了循环链表。