链表:
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
单链表是动态的,长度可以根据需要进行调整。其长度可以不受限制的增长,只在系统内存不足的时候才会提示内存满。它可以通过指向单链表的第一个结点来访问,每一个后续结点都是通过前一个结点的指针域来访问的,单链表末尾结点的指针域通常置空(NULL),表明链表结束。
定义链表:
因为链表结点由两部分组成,所以每个结点都应该声明为结构,每个结点的数据域数据类型取决于应用程序,即处理何种数据。指针域的数据类型是结点自身类型。
struct node
{
int date; //数据域
struct node *next; //指向下一结点的指针域
};
变量定义:
struct node *head,*p,*q;//定义了个指针,每个指针都可以指向struct node类型的结构
它有两个结构成员:date,next
创建链表:
p=(struct node*)malloc(sizeof(struct node));//第一个结点
q=(struct node*)malloc(sizeof(struct node));//q为接下来的结点
head=p;//头指针指向第一个结点
赋值:
p->date=20;
q->date=30;
这时这两个结点还没链接一起,需要下面的语句链接起来:
把由q指向的结构地址存储到p指向的结构的next域中。
p->next=q;
q->next=NULL;
增加一个新节点:
这时,若要再增加一个结点,可以通过链表头或者链表尾插入新结点。一般应在链表头插入新结点,这是因为链表尾往往没有指针指向它。通过链表尾插入新结点时,必须从链表头到链表尾遍历整个链表才行。从链表头插入结点相对较高效。
这里q指向最后一个结点,所以不用遍历整个链表,可以直接在最后插入新结点。
p=(struct node*)malloc(sizeof(struct node));
p->date=40;
q->next=p;
p->next=NULL;
单链表的创建与遍历:
#include<stdio.h>
#include<stdlib.h>
/*该程序通过创建了一个包含4个结点的单链表,使用malloc()函数申请结点空间,并把新结点空间,
并把新结点链接到了链表表尾*/
struct node //链表结点
{
int date;//数据域
struct node* next;//指针域
};
typedef struct node Node;//将链表命名为Node
int main(void)
{
struct node *head, *p, *q;//定义了3个指针变量,每个指针变量都可以指向 struct node类型的结构
p = (struct node*)malloc(sizeof(struct node*));//第一个结点
p->date = 20;//第一个结点赋值20
head = p;//头指针指向第一个结点
for (int i = 1; i <=3; i++)
{
q = (Node*)malloc(sizeof(Node));//q指向新申请的结点
q->date = (i + 2) * 10; //新结点数据域赋值
p->next = q; //新结点链接到表尾
p = q; //p指向尾结点
}
p->next = NULL;
printf("链表的头指针的值:%d 地址为: %#x\n", *head,head);
printf("链表结点的地址:");
for (Node* p = head; p != NULL; p = p->next)//遍历链表,输出每个结点的地址
{
printf("%#x\t", p);
}
printf("\n");
printf("链表结点的内容:");
for (Node*p = head;p!=NULL;p=p->next)//遍历链表,输出每个结点的数据域,指针域
{
printf("%d %#x\t", p->date, p->next);
}
return 0;
}
运行结果为:
链表的头指针的值:20 地址为: 0xff5a88
链表结点的地址:0xff5a88 0xff5ab8 0xff5940 0xff5978
链表结点的内容:20 0xff5ab8 30 0xff5940 40 0xff5978 50 0