链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
单链表是一种链式存取的数据结构,,链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示的线性表称作线性链表(单链表),单链表是链式存取的结构。
对于链表的每一个结点,我们使用结构体(struct)进行设计,其主要内容有:
其中,DATA数据元素,可以为你想要储存的任何数据格式,可以是数组,可以是int,甚至可以是结构体(这就是传说中的结构体套结构体)
NEXT为一个指针,其代表了一个可以指向的区域,通常是用来指向下一个结点,链表的尾部NEXT指向NULL(空),因为尾部没有任何可以指向的空间了
初始化
同任何的结构,类型一样,链表也需要初始化操作,初始化是创建一个单链表的前置节点并向后逐步添加节点,一般来说,我们所谓的初始化单链表一般指的是申请结点的空间,同时对一个结点辅以空值(NULL),其代码可以表示为:
LinkedList listinit(){
Node *L;
L=(Node*)malloc(sizeof(Node)); //开辟空间
if(L==NULL){ //判断是否开辟空间失败,这一步很有必要
printf("申请空间失败");
//exit(0); //开辟空间失败可以考虑直接结束程序
}
L->next=NULL; //指针指向空
}
创建单链表
单链表的创建分为头插法和尾插法
头插法
头插入法和尾插入法两者并无本质上的不同,都是利用指针指向下一个结点元素的方式进行逐个创建,只不过使用头插入法最终得到的结果是逆序的。
该方法从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后。
代码1:
//单链表的建立1,头插法建立单链表
LinkedList LinkedListCreatH() {
Node *L;
L = (Node *)malloc(sizeof(Node)); //申请头结点空间
L->next = NULL; //初始化一个空链表
int x; //x为链表数据域中的数据
while(scanf("%d",&x) != EOF) {
Node *p;
p = (Node *)malloc(sizeof(Node)); //申请新的结点
p->data = x; //结点数据域赋值
p->next = L->next; //将结点插入到表头L-->|2|-->|1|-->NULL
L->next = p;
}
return L;
代码2:
尾插法
该方法是将新结点逐个插入到当前链表的表尾上,为此必须增加一个尾指针r,使其始终指向当前链表的尾结点,否则就无法正确的表达链表。
代码:
//单链表的建立2,尾插法建立单链表
LinkedList LinkedListCreatT() {
Node *L;
L = (Node *)malloc(sizeof(Node)); //申请头结点空间
L->next = NULL; //初始化一个空链表
Node *r;
r = L; //r始终指向终端结点,开始时指向头结点
int x; //x为链表数据域中的数据
while(scanf("%d",&x) != EOF) {
Node *p;
p = (Node *)malloc(sizeof(Node)); //申请新的结点
p->data = x; //结点数据域赋值
r->next = p; //将结点插入到表头L-->|1|-->|2|-->NULL
r = p;
}
r->next = NULL;
return L;
}
另外还需要考虑带不带头节点的问题
以下是两者的对比:
看了你以前的分享,这质量太高了吧orz