1.单链表结构体特点
typedef struct LNode { //单链表结构类型
ElemType data; //数据域
struct LNode *next; //指针域(指向下一个结构体的起始地址)
} LNode, *LinkList;
【注】单链表结构体名字不能省略
头指针:
链表中第一个节点的存储位置,用于表示单链表
头结点:
在单链表第一个节点之前附加的一个节点,为了操作上的方便
如果链表有头节点,头指针永远指向头节点,不论链表是否为空,头指针均不为空,头指针时链表的必要元素,标识链表 头节点不是必须的(学习是必须的)
优点 | 缺点 |
---|---|
插入和删除操作不需要移动元素,只需要修改指针。 | 单链表附加节点指针域,也存在浪费存储空间的缺点。 |
不需要大量的连续存储空间。 | 查找操作时需要从头遍历,依次查找,不能随机存取。 |
插入操作
0. 判断 a."表头插入元素"|b."中间插入元素"|c."表尾插入元素"
1.创建新节点(q), 给新节点申请空间 malloc
a."表头插入元素"(插入位置是a1)
2.让q的指针域next指向ai
3.让原有的头节点指针域指next向q
b."中间插入元素"(插入位置是i-1与i直接)
2.让q的指针域next指向ai
3.让ai-1的指针域next指向q
c."表尾插入元素"(插入位置是an,后面)
2.让an的指针域next指向q
3.给q的next赋值为NULL
头插法新建链表
流程:
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
void List_head_insert(LinkList &L){
L=(LinkList) malloc(sizeof (LNode));
L->next=NULL;
LNode *s;
ElemType x;
scanf("%d", &x);
while (x!=9999){
s=(LinkList) malloc(sizeof (LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
}
void log(LinkList L){
L=L->next;
while(L!=NULL){
printf("%3d", L->data);
L=L->next;
}
printf("\n");
}
int main(){
LinkList L;
List_head_insert(L);
log(L); //打印链表
return 0;
}
尾插法新建链表
流程:
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
void List_tail_insert(LinkList &L){
// 2.1申请头节点
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
// 2.2定义尾指针r
LNode *s, *r=L; //s指向新节点 r指向链表尾
ElemType x;
// 3.读取第一个元素
scanf("%d", &x);
// 2.2定义位置在r
while(x!=9999){
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
r->next=s; // 新节点给尾节点的next指针
r=s; // r指向新的尾部
scanf("%d",&x);
}
r->next=NULL;
}
void log(LinkList L){
L=L->next;
while(L!=NULL){
printf("%3d", L->data);
L=L->next;
}
printf("\n");
}
int main(){
LinkList L;
List_tail_insert(L);
log(L); //打印链表
return 0;
}
查询操作
- 按位置查找,查找第i个(头节点不被计算成第一个节点)
流程:
- 按值查找
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
void List_head_insert(LinkList &L){
L=(LinkList) malloc(sizeof (LNode));
L->next=NULL;
LNode *s;
ElemType x;
scanf("%d", &x);
while (x!=9999){
s=(LinkList) malloc(sizeof (LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
}
void List_tail_insert(LinkList &L){
// 2.1申请头节点
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
// 2.2定义尾指针r
LNode *s, *r=L; //s指向新节点 r指向链表尾
ElemType x;
// 3.读取第一个元素
scanf("%d", &x);
// 2.2定义位置在r
while(x!=9999){
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
r->next=s; // 新节点给尾节点的next指针
r=s; // r指向新的尾部
scanf("%d",&x);
}
r->next=NULL;
}
// 按位置查找
LinkList GetElem(LinkList L, int pointer){
if (pointer<0){
return NULL;
}
int i=0;
while (L && i<pointer){
L=L->next;
i++;
}
return L;
}
// 按值查找
LinkList LocateElem(LinkList L, ElemType val){
while(L){
if(L->data==val){ //如果找到返回节点的指针
return L;
}
L=L->next; //如果没有找到向后遍历
}
return NULL;
}
void log(LinkList L){
L=L->next;
while(L!=NULL){
printf("%3d", L->data);
L=L->next;
}
printf("\n");
}
int main(){
LinkList L;
List_tail_insert(L);
log(L); //打印链表
LinkList searchByKey=GetElem(L,3);
if (searchByKey!=NULL){
printf("Succeeded in searching by serial number\n");
printf("%d\n",searchByKey->data);
}
LinkList searchByVal = LocateElem(L, 3);
if(searchByVal!=NULL){
printf("search by value succeeded\n");
printf("%d\n",searchByVal->data);
}
return 0;
}
在第i个位置插入元素
流程:
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 尾插法新建链表
void List_tail_insert(LinkList &L){
// 2.1申请头节点
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
// 2.2定义尾指针r
LNode *s, *r=L; //s指向新节点 r指向链表尾
ElemType x;
// 3.读取第一个元素
scanf("%d", &x);
// 2.2定义位置在r
while(x!=9999){
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
r->next=s; // 新节点给尾节点的next指针
r=s; // r指向新的尾部
scanf("%d",&x);
}
r->next=NULL;
}
// 按位置查找
LinkList GetElem(LinkList L, int pointer){
if (pointer<0){
return NULL;
}
int i=0;
while (L && i<pointer){
L=L->next;
i++;
}
return L;
}
// 打印链表
void log(LinkList L){
L=L->next;
while(L!=NULL){
printf("%3d", L->data);
L=L->next;
}
printf("\n");
}
// 在第i个位置插入
// 往第i个位置插入不会改变L
bool List_front_insert(LinkList L, int pointer, ElemType val){
LinkList p=GetElem(L, pointer);
printf("%d\n", p->data);
if (p==NULL){
return false;
}
LinkList q=(LinkList) malloc(sizeof(LNode));
q->data=val;
q->next=p->next;
p->next=q;
return true;
}
int main(){
LinkList L;
// List_head_insert(L);
List_tail_insert(L);
// 在第i个位置插入
bool ret=List_front_insert(L, 2, 99);
if (ret){
printf("insert success\n");
} else{
printf("insert failed\n");
}
log(L); //打印链表
return 0;
}
删除操作
流程:
0.判断 a."表头删除元素"(删除位置是a1)|
b."中间删除元素"(删除位置i)|
c."表尾删除元素"(删除位置是an)
1. 查找删除位置i的前驱节点p位置是i-1 q=p.next (q是当前要删除的节点)
2. 把q的指针域next(位置是ai+1)赋值给p的指针域next(位置是ai-1)
3. q断链后free掉
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 尾插法新建链表
void List_tail_insert(LinkList &L){
// 2.1申请头节点
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
// 2.2定义尾指针r
LNode *s, *r=L; //s指向新节点 r指向链表尾
ElemType x;
// 3.读取第一个元素
scanf("%d", &x);
// 2.2定义位置在r
while(x!=9999){
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
r->next=s; // 新节点给尾节点的next指针
r=s; // r指向新的尾部
scanf("%d",&x);
}
r->next=NULL;
}
// 按位置查找
LinkList GetElem(LinkList L, int pointer){
if (pointer<0){
return NULL;
}
int i=0;
while (L && i<pointer){
L=L->next;
i++;
}
return L;
}
// 打印链表
void log(LinkList L){
L=L->next;
while(L!=NULL){
printf("%3d", L->data);
L=L->next;
}
printf("\n");
}
// 在第i个位置插入
// 往第i个位置插入不会改变L
bool List_front_insert(LinkList L, int pointer, ElemType val){
LinkList p=GetElem(L, pointer);
if (p==NULL){
return false;
}
LinkList q=(LinkList) malloc(sizeof(LNode));
q->data=val;
q->next=p->next;
p->next=q;
return true;
}
// 单链表删除操作
// 删除操作时不会改变L
bool List_front_delete(LinkList L, int pointer){
//q是当前要删除的节点
LinkList q= GetElem(L, pointer);
//p是当前要删除的节点的前驱
LinkList p= GetElem(L, pointer-1);
if(p==NULL){
return false;
}
//断链
p->next=q->next;
free(q);
return true;
}
int main(){
LinkList L;
// List_head_insert(L);
List_tail_insert(L);
// 单链表删除
List_front_delete(L, 2);
log(L); //打印链表
return 0;
}