链表优点:链表各个节点个数可以灵活变动,学生多时可以增加节点,少时可以减少节点,链表不要求存储空间连续,空间利用率高
链表:链表中每个节点在内存中位置不一定连续,所以每一节点中一定有个字段存放下一个节点的地址,如此便可已形成链表结构
链表的每个节点在内存中位置不一定连续
每一节点中一定有一个字段存放下一个节点的地址
链表的分类:单向链表、单向循环链表、双向链表、双向循环链表
单像链表的标准结构:
struct Node
{
类型 data;//存放数据比如学生的学号
Node * next;//存放下一个节点的地址(必须有)
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//定义单向链表的节点
struct Node
{
//数据成员,可以是原始类型,也可以是struct,enum,union
char name[32];
//一定不能缺的成员
struct Node * next;//指向下一个节点的指针
};
int main()
{
//产生3个节点
struct Node stu1;
struct Node stu2;
struct Node stu3;
//给节点的数据赋值
strcpy(stu1.name,"学生A");
strcpy(stu2.name,"学生B");
strcpy(stu3.name,"学生C");
//上面三个节点是散乱分布的,需要把他们穿成链表
//stu1作为头节点,stu3作为尾节点
stu1.next=&stu2;
stu2.next=&stu3;
stu3.next=NULL;//stu3是最后一个节点,所以next为NULL
//打印链表,从链表头开始
struct Node *pHead = &stu1;//头指针指向第一个节点
while(pHead!=NULL)
{
printf("%s ",pHead->name);
pHead = pHead->next;//获取下一个节点的内存地址
}
printf("\n");
return 0;
}
向链表的尾部插入节点
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
//定义单向链表的节点
struct Node
{
//数据成员,可以是原始类型,也可以是struct,enum,union
char name[32];//节点的数据成员
//一定不能缺的成员
struct Node *next;//指向下一个节点的指针
};
int main()
{
//定义两个节点指针,一个指向头节点(方便遍历),一个指向尾节点(方便插入)
struct Node *pHead = NULL;
struct Node *pTail = NULL;//空链表的时候
//让用户可以随时输入学生
while(1)
{
printf("请输入学生姓名,quit(退出) print(打印):\n");
char name[32] = {
0};
scanf("%s",name);
if(strcmp(name,"quit")==0)
break;
else if(strcmp(name,"print")==0)
{
struct Node *pNode = pHead;//不要改变pHead的值,让他一直指向头部
while(pNode!=NULL)
{
printf("%s ",pNode -> name);
pNode = pNode->next;//指向下一个节点
}
printf("\n");
}
else
{
//struct Node stu;//可以定义节点,但是这样定义的话离开}内存就释放了,stu是局部变量
//分配节点堆内存,除非free,否则一直有效
struct Node *pNode = (struct Node*)malloc(sizeof(struct Node));
strcpy(pNode->name,name);
pNode->next = NULL;//因为这个节点即将作为尾部节点
//把节点放在链表中
//判断是不是第一个节点
if(pHead==NULL)
{
pHead = pNode;
pTail = pNode;//第一个节点既是头,又是尾部
}
else
{
pTail -> next = pNode;//让一个尾巴的next = 新节点
pTail = pNode;//让pTail始终指向最新的尾巴
}