特点:
- 有一个head指针变量,它存放头结点的地址,称之为头指针。
- 头节点的指针域head->next,存放首元结点的地址。
- 每个节点都包含一个数据域和指针域,数据域存放数据,指针域存放下一节点的地址。
- 最后一个结点不在指向其他结点,它的指针域存放空指针。
- 链表依靠指针相连不需要占用一块连续的内存空间。
- 随着处理数据量的增加,链表可以无限制的延长。在插入和删除操作中,只需修改相关节点指针域的链接关系,不需要大量的改变数据的实际储存位置。链表的使用,可以使程序的内存利用率和时间效率大大增加。
单链表初始化
链表结点数据类型选用结构体类型(C语言允许结构体类型递归定义)。 例如建立一个链表表示一个班级,其中链表的结点表示学生。
typedef struct node { char name[20]; int number; //数据域 struct node *next; //指针域 }Node,*LinkList;
其中Node是结构体类型,LinkList是结构体指针类型。
单链表的初始化就是创建一个头节点。
LinkList Init() { LinkList head; head = (Node*)malloc(sizeof(Node)); head->next = NULL; return head; }
单链表的建立
1、尾插法
在尾部插入新结点建立单链表。 从一个空表开始,重复读入数据,将读入数据存入新结点的数据域中,然后将新结点差入到当前链表的表尾上,直至读入结束标志为止。
void Build(LinkList head) { LinkList r, s; char name[20]; int number; r = head; printf("请输入学生的姓名和学号\n"); while (1) { scanf("%s%d", name,&number); if (number == 0) break; s = (Node*)malloc(sizeof(Node)); s->number = number; strcpy(s->name, name); r->next = s; r = s; } r->next = NULL; }
头插法
在单链表头部插入新结点。 从一个空表开始重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头结点之后,直至读入结束标志为止。
void Build(LinkList head) { LinkList s; int number; char name[20]; printf("请输入学生姓名和学号\n"); while (1) { scanf("%s%d", name, &number); if (number == 0) break; s = (Node*)malloc(sizeof(Node)); s->number = number; strcpy(s->name, name); s->next = head->next; head->next = s; } }
单链表的遍历
定义一个临时指针p,使其指向链表的首元结点。在while循环中,每输出一个结点的内容,就移动p至下一个结点。
void OutPut(LinkList head) { LinkList p=head->next; printf("学生信息如下\n"); while (p) { printf("姓名:%s ", p->name); printf("学号:%d\n", p->number); p = p->next; } }
单链表的查询
定义指针变量p,使其指向链表的首元结点。如果某结点的值和给定值不同,则移动p这下一个结点。直至某结点的值和给定的值相同,返回该结点地址。
LinkList Search(LinkList head, char name[]) { LinkList p = head->next; while (p) { if (strcmp(p->name, name) != 0) p = p->next; else break; } if (p == NULL) printf("EOROR\n"); return p; }
单链表的插入
从链表的头结点开始,找到链表第i-1个结点的地址p,在第i-1个结点后插入新结点。 插入时,先将新结点的指针指向第i个结点,再将第i-1个结点的指针指向新结点。
void Inser(LinkList head,int i) { LinkList p = head, s; int j=0; while (j < i - 1 && p) { p = p->next; j++; } if (p) { printf("请输入待添加的学生的姓名和学号\n"); s = (Node*)malloc(sizeof(Node)); scanf("%s%d", s->name, &s->number); s->next = p->next; p->next = s; } }
单链表的删除
首先利用循环找到要删除的结点p和p之前的结点q(将Search函数稍作改变)。如果该节点存在,则连接待删除结点两边的结点(q->next = p->next),并使用free函数将p指向的内存空间释放。
void Delete(LinkList head,char name[20]) { LinkList p = head->next; LinkList q = p->next; while (1) { if (strcmp(p->name, name) != 0) { q = p; p = p->next; } else break; } if (q== NULL || p == NULL) printf("EORROR\n"); else { q->next = p->next; free(p); } }
单链表的长度
从首元点开始,依次遍历链表的所有结点,并同时统计结点个数。最后返回结点个数。
int Length(LinkList head) { LinkList p = head->next; int count = 0; while (p) { p = p->next; count++; } return count; }