1.链表是由如干个节点所组成的(链表的各个节点结构是完全相似的),节点是由有效数据和指针组成的,有效数据区是用来储存数据的,指针是用来指向下一个节点的首地址,从而构成链表。
2.链表是用来解决数组的大小不能动态扩展的问题,灵活性比数组好,和数组一样也是用来存储数据的,链表需要分配多少个动态数据分配多少个,不占用额外内存。
3.单链表的实现
(1)单链表的节点构成
有效数据部分,和指针部分
(2)定义的struct
node只是一个结构体,本生没有变量生成,也不占用内存,结构体定义相当于为链表节点定义了一个模板,但是还没有一个节点,将来在实际创建一个链表时需要一个节点用这个模板复制一个即可
3.堆内存的申请和使用
(1)链表的内存要求比较灵活,不能用栈,也不能用data数据段,只能用堆内存
(2)使用堆内存创建一个链表节点的步骤:1、申请堆内存,大小为一个节点的大小(检查申请结果是否正确);2、清理申请到的堆内存;3、把申请到的堆内存当做一个新节点;4、填充这个新节点的有效数据和指针区域。
4.链表的头指针
(1)头指针并不是节点,而是一个普通指针,只占4个字节,它的类型是struct node *型,所以他才能指向链表的节点.
(2)访问链表中各个节点的数据只能用头指针,因为实际中,我们保存链表的时候是不会保存各个节点的指针的,只能通过头指针来访问链表节点。
(3)前一个节点的pNext指针能帮我们找到下一个节点。
一个一个的创建节点:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//构建链表节点
struct node
{
int data; //有效数据
struct node *pNext; //指向下一个节点的指针
};
int main(void)
{
//定义头指针
struct node *pHeader = NULL;
//创建一个链表节点
struct node *p1 = (struct node *)malloc(sizeof(struct node));
if(NULL == p1)
{
printf("malloc error\n");
return -1;
}
//清理申请到的堆内存
// void bzero(void *s, size_t n);
bzero(p1,sizeof(struct node));
//填充节点
p1->data = 1;
p1->pNext = NULL; //将来要指向下一个节点的首地址
pHeader = p1;
struct node *p2 = (struct node *)malloc(sizeof(struct node));
if(NULL == p2)
{
printf("malloc error\n");
return -1;
}
//清理申请到的堆内存
// void bzero(void *s, size_t n);
bzero(p2,sizeof(struct node));
//填充节点
p2->data = 2;
p1->pNext = p2; //将来要指向下一个节点的首地址
struct node *p3 = (struct node *)malloc(sizeof(struct node));
if(NULL == p3)
{
printf("malloc error\n");
return -1;
}
//清理申请到的堆内存
// void bzero(void *s, size_t n);
bzero(p3,sizeof(struct node));
//填充节点
p3->data = 3;
p2->pNext = p3; //将来要指向下一个节点的首地址
//访问链表中的有效数据(只能用pHeader访问)
//pHeader->data; //pHeader->data等同于p1->data
printf("node1 data = %d\n",pHeader->data);
printf("p1->data = %d\n",p1->data);
printf("node2 data = %d\n",pHeader->pNext->data);
printf("p2->data = %d\n",p2->data);
printf("node3 data = %d\n",pHeader->pNext->pNext->data);
printf("p3->data = %d\n",p3->data);
return 0;
}
将创建节点的程序封装成一个函数:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//构建链表节点
struct node
{
int data; //有效数据
struct node *pNext; //指向下一个节点的指针
};
//函数功能,创建链表节点
//返回值:指针,指向我们本函数新创建的一个节点的首地址
struct node *creat_node(int data)
{
//创建一个链表节点
struct node *p = (struct node *)malloc(sizeof(struct node));
if(NULL == p)
{
printf("malloc error\n");
return NULL;
}
//清理申请到的堆内存
// void bzero(void *s, size_t n);
bzero(p,sizeof(struct node));
//填充节点
p->data = data;
p->pNext = NULL; //将来要指向下一个节点的首地址
return p;
}
int main(void)
{
//定义头指针
struct node *pHeader = NULL;
pHeader = creat_node(1);
pHeader->pNext = creat_node(2);
pHeader->pNext->pNext = creat_node(3);
//访问链表中的有效数据(只能用pHeader访问)
printf("node1 data = %d\n",pHeader->data);
printf("node2 data = %d\n",pHeader->pNext->data);
printf("node3 data = %d\n",pHeader->pNext->pNext->data);
return 0;
}