数组作为存放数据的集合,可以用来申请内存。但是数组的大小在定义的时候必须事先定义好,一旦定义好在程序中就不能再调整。供大于求,就会内存空间的浪费。我们希望构造动态的数组,随时可以调整数组的大小,用来满足不同问题的需求。链表就是我们需要的动态的数组。他是在时程序执行的过程中根据需要有数据存储,就就向系统要求申请存储空间,不会造成存储区空间的浪费。链表是一种复杂的数据结构。其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表、双向链表。
1.1 单链表
单链表有一个头节点h e a d,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型,节点有两个成员:整型成员(实际需要保存的数据)和指向下一个结构体类型节点的指针即下一个节点的地址(事实上,此单链表是用于存放整型数据的动态数组)。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为N U L L。
图还给出这样一层含义,链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。
看一下链表节点的数据结构定义:
struct node
{
int num;
struct node *p
}
在链表节点的定义中,除了一个整型的成员外,成员p是指向与节点类型完全相同的指针。在链表节点的数据结构中,非常特殊的一点就是结构体内指针域的数据类型使用了未定义成功的数据类型。这是在C语言中唯一规定可以先用后定义的数据结构。
2.1单链表创建的主要步骤就是:
- 定义链表的数据结构
- 创建一个空的链表
- 利用malloc()函数向系统申请分配一个节点
- 利用calloc()或malloc()函数向系统申请内存
- 将新节点的指针成员赋值为空。若是空表,将新节点连接到表头。若是非空表,将新节点接到表尾。
- 判断一下是否有后续的节点要插入链表,如果有,就继续申请内存存放数据,反之就结束
2.2 链表的输出主要有以下几步
- 找到表头
- 若是非空表头,输出节点的值成员,空表直接退出
- 跟踪链表的增长,即找到下一个节点的地址
2.3 创建链表
创建链表的方法主要有三种方法:
头插法、尾插法、有序插法
2.3.1 头插法
新开辟的节点总是作为表头
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/********************
* 要求:创建一个存放整数的(输入负数时做结束标志)的单链表
* 时间:2018-11-8
* @说明:采用头插法
*********************/
struct node
{
int num;
struct node *next;
};
//创建表利用头插法插入数据
struct node *create(struct node *head)
{
struct node *phead,*ptail;
phead=ptail=(struct node *)malloc(sizeof(struct node));
if(phead==NULL)
{
printf("内存分配失败,建立链表失败\n");
}
memset(phead,0,sizeof(struct node));
scanf("%d",&phead->num);
phead->next=NULL;
while(phead->num>0)
{
if(head==NULL){
head=phead;
}else{
phead->next=head;//==原来的第一个节点接在新开辟节点的后面
head=phead;//新开辟的节点作为头节点,也就是插在表头
//===为下一个数据开辟新的节点
}
phead=(struct node *)malloc(sizeof(struct node));
// memset(phead,0,sizeof(struct node));
scanf("%d",&phead->num);
phead->next=NULL;
}
return head;
}
void list_printf(struct node *head)
{
struct node *temp;
temp=head;
if(head!=NULL)
do {
printf("头插法输出%d\n",temp->num);
temp=temp->next;
}while(temp!=NULL);
printf("\n");
}
void main()
{
struct node *head;
head=create(head);
list_printf(head);
}
2.3.2 尾插法
在链表的创建过程中,链表的头指针是非常重要的参数。因为对链表的输出和查找都是从链表的头开始的,所以创建链表成功后,要返回的一个链表的头节点的地址就是头指针。如下图就是尾插法的过程
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
/********************
* 要求:创建一个存放整数的(输入负数时做结束标志)的单链表
* 时间:2018-11-8
*
*********************/
//===定义一个节点
struct node
{
int num;
struct node *next;
};
struct node *create(struct node *head)//==函数返回的是与节点相同类型的指针
{
//定义两个新节点
struct node *phead,*ptail;
//为新节点开辟内存
phead=ptail=(struct node*)malloc(sizeof(struct node));
scanf("%d",&phead->num);
//====表为空
head=NULL;
while(phead->num>0)
{
if(head==NULL) head=phead;
else ptail->next=phead;
ptail=phead;
phead=(struct node*)malloc(sizeof(struct node));
scanf("%d",&phead->num);
}
ptail->next=NULL;
return head;///===返回链表的头指针
}
void list_printf(struct node *head)
{
struct node *temp;
temp=head;
if(head!=NULL)
do{
printf("%d",temp->num);
temp=temp->next; ///==跟踪链表增长
}while(temp!=NULL);
}
int main()
{
struct node *head;
head=create(head);
list_printf(head);
}
今天就写到这后面持续更新。。。。。。。