链表也是线性表的一种,用于存取逻辑关系为线性的数据,但是和顺序表不同,链表的存储结构是链式存储,在内存中不连续,例如数据在内存中存储可能是下图:
要把链表的节点连接起来就需要通过指针来操作
所以在链表中,每个数据元素可以配有一个指针用于找到下一个元素即节点,这意味着,链表上的每个“元素”都长下图这个样子:
逻辑结构:线性结构??
存储结构:链式存储结构
特点:内存中不连续,通过指针链接
解决顺序表中的问题:长度固定和插入删除的麻烦
struct?node
{
????int?data;//数据域
????struct?node?*next;//指针域
}//
有头链表:存在一个头节点,(只作为链表开头,不存放数据)数据域无效,指针域有效。
无头链表:每一个节点的数据域和指针域都有效
#include?<stdio.h>
typedef char?datatype;
typedef struct node
{
????datatype?data; //数据域,用来存放数据。
struct node *next; //指针域,用来存放下一个节点的地址。
} link_node_t, *link_list_t;
//?link_node_t?A;?等同于?struct?node?A;
//?link_list_t?p;?等同于?struct?node?*p;
int main(int?argc, char const *argv[])
{
//1.定义4个节点
link_node_t?A?= {'a', NULL};
link_node_t?B?= {'b', NULL};
link_node_t?C?= {'c', NULL};
link_node_t?D?= {'d', NULL};
//2.将四个节点连接起来
????A.next?= &B;
????B.next?= &C;
????C.next?= &D;
//3.定义一个头指针,指向第一个节点。用于遍历链表。
link_list_t?p?= &A;
//4.遍历无头链表
while (p?!= NULL) //判断p所指是否为空,不为空则说明指向链表节点。
{
printf("%c?",?p->data); //打印节点中数据域
????????p?=?p->next; //让p指向下一个节点
}
printf("\n");
return 0;
}
#include?<stdio.h>
typedef char?datatype;
typedef struct node
{
????datatype?data; //数据域,用来存放数据。
struct node *next; //指针域,用来存放下一个节点的地址。
} link_node_t, *link_list_t;
//?link_node_t?A;?等同于?struct?node?A;
//?link_list_t?p;?等同于?struct?node?*p;
int main(int?argc, char const *argv[])
{
//1.定义4个节点
link_node_t?A?= {'a', NULL};
link_node_t?B?= {'b', NULL};
link_node_t?C?= {'c', NULL};
link_node_t?D?= {'d', NULL};
//2.将四个节点连接起来
????A.next?= &B;
????B.next?= &C;
????C.next?= &D;
//3.定义一个头节点,数据无效,指针域指向第一个节点。
link_node_t?h?= {'\0', &A};
//4.定义一个头指针,指向头节点。
link_list_t?p?= &h;
//5.遍历有头单项链表
#if?0
//方法一:
????p?=?p->next; //跨过头节点,指向第一个节点。
while (p?!= NULL)
{
printf("%c?",?p->data);
????????p?=?p->next;
}
printf("\n");
#else
//方法二:
while (p->next?!= NULL)
{
????????p?=?p->next;
printf("%c?",?p->data);
}
printf("\n");
#endif
return 0;
}
写一个有头单项链表,用于保存输入的学生成绩,实现一输入学生成绩就创建一个新的节点,将成绩保存起来。再将该节点链接到链表的尾,直到输入-1结束。
要求:每个链表的节点由动态内存分配得到?,?也就是用malloc。
过程:
先实现输入学生成绩,直到-1结束:
#include?<stdio.h>
typedef struct node_t
{
int?score;
struct node_t *next;
}link_node_t,* link_list_t;
int main(int?argc, char const *argv[])
{
int?score?= -1;
while (1)
{
scanf("%d", &score);
if (score?== -1)
break;
}
//1.malloc申请空间,创建一个新节点用于保存学生成绩。
//2.将新节点链接到连表的尾部
return 0;
}
继续实现malloc申请新节点存入学生成绩然后连接到链表尾部:
#include<stdio.h>
#include<stdlib.h>
typedef struct node_t
{
int?score;
struct node_t *next;
}link_node_t,*link_list_t;
int main(int?argc, char const *argv[])
{
int?score?;
link_list_t?pnew=NULL;//新节点地址指针
link_list_t?ptail=NULL;//链表尾巴地址指针
//1.malloc申请空间,创建一个新节点用于保存学生成绩。
link_list_t?h=(link_list_t)malloc(sizeof(link_node_t)); //创建一个头节点,用头指针h指向头节点
if(NULL==h)//判断成功开辟空间
{
perror("h?malloc?err");
return -1;
}
????h->score='\0';//头节点初始化
????h->next=NULL;
????ptail=h;//指向头节点
//2、循环输入学生成绩,直到-1结束。并且新输入一个成绩创建一个新节点存入,然后把新节点链接到链表尾巴
while (1)
{
scanf("%d",&score);
getchar();
if(score==-1)
{
break;
}
else
{
????????????pnew=(link_list_t)malloc(sizeof(link_node_t));//(1)创建一个新的节点用来保存输入学生成绩
????????????pnew->next=NULL;//新节点指针域赋空值
????????????pnew->score=score;//(2)对新节点的数据域和指针域进行赋值
????????????ptail->next=pnew;//(3)将新节点连接到链表尾部
????????????ptail=pnew; //(4)链表延长一个新节点,需要将尾指针移动到新的节点作为尾巴
}
}
//3.遍历有头链表
while (h->next!=NULL)//判断p是否指向为空,若不为空则说明指向了下一个节点
{
????????h=h->next;//将下一个节点地址赋值给p
printf("%d?",h->score);
}
puts("?");
return 0;
}