无论数据是如何存储的,对改数据的操作都是一样的
我们至少可以通过两种结构来存储数据
数组 | 链表 |
---|---|
存取速度快 | 查找某个位置的元素效率很低 |
插入和删除元素的效率很低(在数组上插入一个元素,我们可能需要移动已经存在的元素,腾出位置以便新元素插入该位置) | 插入删除元素效率高 |
数组的存储地址 = 数组的起始地址+偏移量 | |
需要一个连续的很大的内存 | 不需要一个连续的很大的内存 |
专业术语:
头结点
- 头结点的数据类型和首节点的类型是一模一样的
- 头结点是首节点前面那个节点
- 头结点并不存放有效数据
- 设置头结点的目的是为了方便对链表的操作
头指针
- 存放头结点地址的指针变量
首节点
- 存放第一个有效数据的节点
尾节点
- 存放最后一个有效数据的节点
确定一个链表需要的参数:
一个 头指针
什么是链表?
链表是一种用来存储数据集合得数据结构
- 元素通过指针依次相连
- 最后一个元素的指针为空(NULL)
- 它不会浪费空间,但会需要消耗额外的内存空间存储指针
- 动态地进行内存单元分配的一种结构
单链表
singly linked list
单链表包括一组结点,每个结点都有一个next指针域,用来存储指向(逻辑上)下一个元素对应结点的指针,最后一个结点的next指针域的值为NULL,预示着已经达到链表的尾部。
struct node{
int data;
struct node *next;
};
typedef struct node NODETYPE
main(){
NODETYPE s1, s2, s3, *begin, *p;
s1.data = 100; /*给变量中的data域赋值*/
s2.data = 200;
s2.data = 300;
begin = &s1;
s1.next = &s2; /*使s1的域next指向s2*/
s2.next = &s3;
s3.next = NULL;
p = begin; /*移动p,使之依次指向s1、s2、s3,输出他们data域中的值*/
while(p){
printf(" %d", p->data);
p = p->next; /*p顺序后移*/
}
顺序访问链表中各结点的数据域
void printlist(NODETYPE *head){
NODETYPE *p;
p = head->next;
if(p == '\0')
printf("LINKLSIT IS NULL\n")
else{
printf("head");
do{
printf("->%d",p->data); /*输出当前结点数据域中的值*/
p = p->data; /*move指向下一个结点*/
}while(p!='\0'); /*未到链表尾,继续循环下去*/
}
printf("->end\n");
}