链表
顺序表缺陷
- 空间不够了需要扩容,增容是要付出代价
- 避免频繁扩容,空间满了基本上就是扩充两倍,可能就会导致一定的空间的浪费
- 顺序表要求数据从开始位置连续存储,那么就只能在头部或者中间位置插入删除数据,就需要进行挪动数据,效率低
针对顺序表的缺陷 就设计出了链表
连续的空间 :我们就只记录第一位置的地址就可以了 就可以通过简引用来访问其他的位置地址
单链表
通过指针指向下一个的地址
- 最后指向NULL
- 任意的存储单元来描述不同元素的逻辑关系
数据域 指针域
头指针记录第一个元素的地址 唯一指定
特性:
1.结点在存储器中的位置是任意的,逻辑相邻 物理位置不相邻
2.访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点
3.顺序存取
结点点只有一个指针域的链表
1.带头节点的单链表
如何为空表:head = NULL
优点:便于首元结点的处理
2.不带头节点的单链表
如何为空表:头节点的指针域是否为空
3.双链表
结点有两个指针域的链表
4.循环链表
首尾相接的链表
代码实现:
1.声明结点的类型和指向结点指针类型
pass 1:
typedef struct Lnode //声明结点的类型和指向结点的指针类型
{
ElemType data;//存入的数据 数据域
struct Lnode* next;//一个结构体的指针指向下一个元素的地址 指针类型取决于指针自己本身存储的数据类型 next指向的是下一个结构体中元素的地址 所有next是下一个结构体的类型
}Lnode,*LinkList;//LinkList为指向结构体Lnode的指针类型
注: node *p && LinkList p 等价
pass 2:
学生的学号 姓名 成绩
typedef struct student
{
char num[8];
char name[8];
int score;
struct student* next;
}Lnode_s,*LinkList_s;
规范类型
typedef struct
{
char num[8];
char name[8];
int score;
}ElemTypes;
2.单链表的初始化
//链表初始化 置为空表
void initlist(node *L)
{
L = (node*)malloc(sizeof(node));//开辟一个结点给L
L->next = NULL;//将该结点指向为NULL
}
3.判断是否为空
//判断链表是否为空
void isempty(node* L)
{
if (L->next == NULL)
{
printf("开辟失败!\n");
}
else
{
printf("开辟成功!\n");
}
}
4.清空链表
//清空链表
void qklist(node*L)
{
node* p, * q;
p = L->next;
while (p!=NULL)
{
q = p->next;
free(q);
p = q;
}
L->next = NULL;
}
5.头插入数据
//头插插入数据
void createlist(node *L)
{
node* p;
int i = 1;
int j;
while (i!=0)
{
scanf("%d", &j);
if (j!=-1)
{
p = (node*)malloc(sizeof(node));
p->data = j;
p->next = L->next;//新节点插入到表头
L->next = p;//头节点放最前
}
else
{
i = 0;
}
}
}
6.尾插入数据
void creatfromtail(node* l) {//利用尾插法建立单链表
node* p;//新建一个结点指针
node* r;//再建立一个尾指针
int i = 1;
int j;
r = l;//很重要的一步,令尾指针r指向头结点l,便于做尾插入
while (i != 0) {
scanf("%d", &j);
if (j != -1) {
p = (node*)malloc(sizeof(node));//建立一个新结点
p->data = j;
r->next = p;//尾指针的指针域指向新结点p
r = p;//再让尾指针放在p后面,尾指针永远在最后
}
else
{
i = 0;//输入-1则结束
r->next = NULL;//尾指针的指针域设置为空,表示链表的结束
}
}
}
详细代码:
#define _CRT_SECURE_NO_WARNINGS 1
/*加油!*/
/* -- 单链表的建立 --*/
#include <stdio.h>
#include <stdlib.h>
typedef int elemlist;
/*
* 1.初始化链表
* 2.判断链表是否为空
* 3.清空链表
* 4.销毁链表
* 5.数据头插法/数据尾插法
* 6.查找
* 7.删除
* 8.插入
* 9.打印
*/
//定义结构类型
typedef struct node
{
//数据域
elemlist data;
//指针域
struct node* next;
}node,*listnode;
//链表初始化 置为空表
void initlist(node *L)
{
L = (node*)malloc(sizeof(node));//开辟一个结点给L
L->next = NULL;//将该结点指向为NULL
}
//判断链表是否为空
void isempty(node* L)
{
if (L->next == NULL)
{
printf("开辟失败!\n");
}
else
{
printf("开辟成功!\n");
}
}
//清空链表
void qklist(node*L)
{
node* p, * q;
p = L->next;
while (p!=NULL)
{
q = p->next;
free(q);
p = q;
}
L->next = NULL;
}
//头插插入数据
void createlist(node *L)
{
node* p;
int i = 1;
int j;
while (i!=0)
{
scanf("%d", &j);
if (j!=-1)
{
p = (node*)malloc(sizeof(node));
p->data = j;
p->next = L->next;//新节点插入到表头
L->next = p;//头节点放最前
}
else
{
i = 0;
}
}
}
void creatfromtail(node* l) {//利用尾插法建立单链表
node* p;//新建一个结点指针
node* r;//再建立一个尾指针
int i = 1;
int j;
r = l;//很重要的一步,令尾指针r指向头结点l,便于做尾插入
while (i != 0) {
scanf("%d", &j);
if (j != -1) {
p = (node*)malloc(sizeof(node));//建立一个新结点
p->data = j;
r->next = p;//尾指针的指针域指向新结点p
r = p;//再让尾指针放在p后面,尾指针永远在最后
}
else
{
i = 0;//输入-1则结束
r->next = NULL;//尾指针的指针域设置为空,表示链表的结束
}
}
}
//打印
void printlist(node *L)
{
node* p;
p = L->next;
printf("链表的数据为:\n");
while (p != NULL)
{
printf("%d ", p->data);//首元结点取出数据
p = p->next;
}
}
int main()
{
node L;/*
initlist(&L);*/
//printf("头插入输入数据:\n");
//createlist(&L);
//printlist(&L);
//qklist(&L);
printf("尾插入输入数据:\n");
creatfromtail(&L);
printlist(&L);
return 0;
}