2.3.1单链表的定义
2.3.1单链表的定义



struct LNode{//定义单链表节点类型
ElemType data;//每个节点存放一个数据元素
struct LNode *next;// 指针指向下一个节点
};
struct LNode *p=(struct LNode *)malloc(sizeof(struct LNode));

typedef struct LNode{//定义单链表结点类型
ElemType data;//每个节点存放一个数据元素
struct LNode *next;// 指针指向下一个节点
}LNode,*LinkList;
struct LNode{
ElemType data;
struct LNode *next;
};
typedef struct LNode LNode;
typedef struct LNode *LinkList;

typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
LNode *GetElem(LinkList L,int i){
int j=1;
LNode *p=L->next;
if(i==0)
return L;
if(i<1)
return NULL;
while(p!=NULL && j<i){
p=p->next;
j++;
}
return p;
}
#头插法建立单链表的算法
LinkList List_HradInsert (LinkList &L){
LNode *s;int x;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
scanf("%d",&x);
while(x!=9999){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
return L;
}
#不带头结点的单链表
typedef struct LNode{//定义单链表结点类型
ElemType data;//每个节点存放一个数据元素
struct LNode *next;// 指针指向下一个节点
}LNode,*LinkList;
//初始化一个空的链表
bool InitList(LinkList & L){
L=NULL;//空表,暂时还没有任何结点
return true;
}
void test(){
LinkList L;//生成一个指向单链表的指针
//初始化一个空表
InitList(L);
//...后续代码...
}

#带头结点的单链表
typedef struct LNode{//定义单链表结点类型
ElemType data;//每个节点存放一个数据元素
struct LNode *next;// 指针指向下一个节点
}LNode,*LinkList;
//初始化一个单链表(带头结点)
bool InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));//分配一个头节点
if(L==NULL)//内存不足,分配失败
return false;
L->next = NULL;//头节点之后暂时还没有节点
return true;
}
void test(){
LinkList L;//声明一个指向单链表的指针
//初始化一个空表
InitList(L);
//...后续代码...
}



2.3.2_1单链表的插入和删除
按位序插入(带头节点)
ListInsert(&L,i,e):插入操作

//在第i个位置插入元素e(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e){
if(i<1)
return false;
LNode *p;//指针p指向当前扫描到的结点
int j=0;//当前p指向的是第几个结点
p = L;//L指向头结点,头结点是第0个结点(不存数据)
while (p!=NULL && j<i-1){//循环找到第i-1个结点
p=p->next;
j++;
}
if(p==NULL)//i值不合法
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next=p->next;
p->next=s;//讲结点s连到p之后
return true;//插入成功
}
//线连接后断掉
时间复杂度O(n)
# 按位插入不带头节点
bool ListInsert(LinkList &L,int i,ElemType e){
if(i<1)
return false;
if(i==1){//插入第1个结点的操作与其他结点操作不同
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = L;
L=s;//头指针指向新的结点
return true;
}
LNode *p;//指针p指向当前扫描到的结点
int j=1;//当前p指向的是第几个结点
p=L;//p指向第一个结点(注意不是头结点)
while(p!=NULL&&j<i-1){//循环找到第i-1个结点
p=p->next;
j++;
}
if(p==NULL)//i值不合法
return false;
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next=p->next;
p->next =s;
return true;//插入成功
}
豆包完整可编译
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> // 解决C语言bool类型未知的问题
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
// 按位插入:不带头结点,C语言二级指针修改头指针
bool ListInsert(LinkList *L,int i,ElemType e){
// 位序非法
if(i<1)
return false;
// 特殊处理:插入第1个位置(需修改头指针)
if(i==1){
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = *L; // 解引用二级指针,获取原第一个结点
*L = s; // 解引用二级指针,更新头指针
return true;
}
// i>1 的情况:找第 i-1 个结点
LNode *p;
int j=1;
p = *L; // 解引用二级指针,从第1个数据结点开始遍历
// 向后走到第 i-1 个结点
while(p!=NULL && j<i-1){
p = p->next;
j++;
}
// i过大,无第i-1结点,插入失败
if(p==NULL)
return false;
// 把s插在p后面
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
// 测试函数(可选,验证插入功能)
void PrintList(LinkList L){
LNode *p = L;
while(p != NULL){
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main(){
LinkList L = NULL; // 初始化空链表(不带头结点)
// 测试插入
ListInsert(&L, 1, 10); // 插第1位
ListInsert(&L, 2, 20); // 插第2位
ListInsert(&L, 1, 5); // 插第1位
PrintList(L); // 输出:5 10 20
return 0;
}
#指定结点的后插操作
//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p,ElemType e){
if(p==NULL)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if(s==NULL)//内存分配失败
return false;
s->data = e;//用结点s保存数据元素e
s->next=p->next;
p->next=s;//将结点s连到p之后
return true;
}
指定结点的前插操作

//前插操作:在p结点之前插入元素e
bool InsertPriorNode (LNode *p,ElemTpye e){
if(p==NULL)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if(s==NULL)
return false;
s->next = p->next;
p->next =s;//新结点s连接到p之后
s->data=p->data;//将p中元素复制到s中
p->data=e;//p中元素覆盖为e
return true;
}
//找不到前驱 直接在后面插入一个结点然后给两个值对换!!!
按位删除(带头节点)
bool ListDelect(LinkList &L,int i,ElemType &e){
if(i<1)
return false;
LNode *p;//指针p指向当前扫描到的结点
int j=0;//当前p指向的是第几个结点
p=L;//L指向头结点,头结点是第0个结点(不存数据)
while(p!=NULL && j<i-1){//循环找到第i-1个结点
p=p->next;
j++;
}
if (p==NULL)//i值不合法
return false;
if(p->next ==NULL)//第i-1个结点之后已无其他结点
return false;
LNode *q=p->next;//令q指向被删除结点
e = q->data;//用e返回元素的值
p->next = q->next;//将*q结点从链条中断开
free(q);//释放结点的存储空间
return true;//删除成功
}
O(n)
//删除指定结点p
bool DeleteNode(LNode *p){
if(p==NULL)
return false;
LNode *q=p->next;//令q指向*p的后继结点
p->data = p->next->data;//和后继结点交换数据域
p->next = q->next;//将*q结点从链条中断开
free(q);//释放后继结点的存储空间
return true;
}
如果p是最后一个结点
// 删除指定结点 p(兼容尾结点)
bool DeleteNode(LNode *p, LinkList L){ // 必须传入头指针 L
if(p == NULL)
return false;
// 情况1:p 不是最后一个结点 → 用O(1)妙法
if(p->next != NULL){
LNode *q = p->next;
p->data = q->data;
p->next = q->next;
free(q);
return true;
}
// 情况2:p 是最后一个结点 → 必须从头找前驱
else{
LNode *pre = L;
// 遍历找到 p 的前驱结点
while(pre->next != p){
pre = pre->next;
}
pre->next = NULL; // 断开尾结点
free(p);
return true;
}
}


浙公网安备 33010602011771号