目录
单链表的操作
单链表的插入操作
题目
A和B是两个单链表(带表头结点),其中元素递增有序。设计一个算法,将A和B归并成一个按元素值非递减有序的链表C,C由A和B的结点组成。
思路
(1)已知A、B中的元素都是递增有序的,要使归并后C中的元素依然是有序的,从A,B中挑选出最小的元素插入C的尾部,这样当A、B中的所有元素都插入C中时,C一定是递增有序的。
(2)哪个是最小的元素呢?由于A、B是递增的,因此A中的最小元素是其开始结点中的元素,B也是一样,只需从A、B的开始结点中选出一个较小的来插入到C的尾部即可。
(3)需要注意,A与B中的元素有可能一个已经全部被插入到C中,另一个还没有插完,这时候只需要将没有插完哪个链接到C的尾部即可,两个都可以这样来处理。
代码
#include <stdio.h>
#include <stdlib.h>
// 声明结构体
struct LNode {
int data;
struct LNode *next;
};
/* 创建一个单链表,由用户输入整型测试数据 */
/* 返回一个单链表 */
LNode * createList() {
LNode *head;
LNode *p1,*p2;
p1=p2=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
head=NULL;
int i=0;
while(p1->data!=0) { // 当用户在控制台输入0时结束循环
i+=1;
if(i==1) {
head=p1;
} else {
p2->next=p1;
}
p2=p1;
p1=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
}
p2->next=NULL;
return head;
}
/* 打印单链表 */
/* *list指的是要被打印输出的单链表 */
void printList(LNode *list) {
printf("\n");
while(list!=NULL) { // 循环单链表
printf("%ld\t",list->data); // 打印单链表中的data数据
list=list->next; // 遍历至下一个结点
}
printf("\n"); // 换行
}
/* 归并递增:将两个递增单链表归并成一个递增单链表(不带头节点),返回合并后的递增单链表 */
/* *A指的是递增单链表A;*B指的是递增单链表B;*&C是带头结点的单链表 */
void * merge(LNode *A,LNode *B,LNode *&C) {
LNode *p;
LNode *q;
p=A;// 注意:这里A传入的是不带头节点的单链表,如果A是带头结点的单链表,那么这里应该是p=A->next
q=B;// 注意:这里B传入的是不带头节点的单链表,如果B是带头结点的单链表,那么这里应该是p=B->next
/* 创建一个带头节点的单链表start */
LNode *temp;
C=(LNode *)malloc(sizeof(LNode));// 创建一个带头节点的链表
C->next=NULL;// 设置头节点的下一个结点为NULL
temp=C;// 临时保存头节点,也是尾结点,参与下面的结点连接操作
// (temp既相当于链表的头节点,又相当于链表的尾结点,完成的链表就是head->next)
/* 创建一个带头节点的单链表end */
while(p!=NULL&&q!=NULL) { // 在同时满足p和q链表不为NULL的情况下循环
// 判断p链表中结点的数据是否小于等于q链表中的数据
if(p->data<=q->data) { // 如果p->data比q->data小于等于,那么
// 体现了尾插法的思想
temp->next=p; // 将临时头节点的下一个结点指向p
p=p->next;// 并且p指向下一个结点
temp=temp->next; // 并且temp也指向终端结点
} else { // 反之,如果大,那么将q链表中的该结点添加到temp尾
temp->next=q;
q=q->next;
temp=temp->next;
}
}
if(p!=NULL) { // 处理q链表已经全部插入到新链表,而p链表还剩下些结点,那么将这些结点链接到temp尾
temp->next=p;
}
if(q!=NULL) { // 同上
temp->next=q;
}
}
/* 归并递减:将两个递增单链表归并成一个递减的单链表,返回一个递减的单链表 */
/* *A指的是递增单链表A;*B指的是递增单链表B */
LNode * mergeDe(LNode *A,LNode *B) {
LNode *C,*temp,*p;
LNode *a=A,*b=B;
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
while(a!=NULL&&b!=NULL) {
if(a->data<=b->data) {
// 为什么需要使用临时结点p?因为p要作为插入的新结点使用又要指向终端结点,不能混合交叉使用,所以需要一个临时结点来保存
p=a; // 临时保存a结点,即新要插入到链表头部的新结点
a=a->next; // 到a的下一个结点
p->next=temp->next; // 头插法的经典使用
temp->next=p;
} else {
p=b;
b=b->next;
p->next=temp->next;
temp->next=p;
}
}
while(a!=NULL) {
p=a;
a=a->next;
p->next=temp->next;
temp->next=p;
}
while(b!=NULL) {
p=b;
b=b->next;
p->next=temp->next;
temp->next=p;
}
return C->next;
}
/* 使用尾插法建立单链表,即新添加的元素添加到链表的尾部 */
/* *&C指的是建立的单链表;a[]指的是批量添加的元素数组;n表示数组长度 */
void createListL(LNode *&C,int a[],int n) {
LNode *temp,*node;
// 创建一个带头节点的单链表
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
// 循环遍历数组,批量为链表插入数据
for(int i=0; i<n; i++) { // 循环申请n个结点来接收a中的元素
node=(LNode *)malloc(sizeof(LNode)); // 创建新结点
node->data=a[i]; // 为新结点赋予数据
temp->next=node; // 将原尾结点的下一个结点指向新结点
temp=temp->next; // 指向终端结点,以便接收下一个结点
}
temp->next=NULL; // 所有元素已经填装完成,将终端结点置为NULL
}
/* 使用头插法建立单链表,即新添加的元素添加到链表的头部 */
/* *&C指的是建立的单链表;a[]指的是批量添加的元素数组;n表示数组长度 */
void createListF(LNode *&C,int a[],int n) {
LNode *temp,*node;
// 创建带头节点的单链表
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
for(int i=0; i<n; i++) {
node=(LNode *)malloc(sizeof(LNode));// 新建结点
node->data=a[i];// 为新结点赋值
// 注意:下面两行不能交换位置,否则会进入死循环
node->next=temp->next; // node所指新结点的指针域next指向C的开始结点
temp->next=node; // 头结点的指针域next指向node,使得node成为新的开始结点
}
}
int main() {
/* [0.]创建初始测试单链表 */
LNode *list1,*t1,*t2,*list11,*list22;
LNode *list2,*mergeList,*mergeDeList;
/* [1.]归并递增 */
list1=createList();// 创建测试链表
printList(list1);// 打印单链表
list2=createList();
printList(list2);
merge(list1,list2,mergeList);
printList(mergeList->next);
/* [2.]归并递减 */
list11=createList();// 创建测试链表
printList(list11);// 打印单链表
list22=createList();
printList(list22);
mergeDeList=mergeDe(list11,list22);
printList(mergeDeList);
/* [3.]尾插法 */
int a[]= {1,3,4,6,7,9,2,5,8};
createListL(t1,a,9);
printList(t1->next);
/* [4.]头插法 */
int b[]= {1,3,4,6,7,9,2,5,8};
createListF(t2,b,9);
printList(t2->next);
return 0;
}
测试结果
算法总结
尾插法建立单链表的核心代码:
/* 使用尾插法建立单链表,即新添加的元素添加到链表的尾部 */
/* *&C指的是建立的单链表;a[]指的是批量添加的元素数组;n表示数组长度 */
void createListL(LNode *&C,int a[],int n) {
LNode *temp,*node;
// 创建一个带头节点的单链表
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
// 循环遍历数组,批量为链表插入数据
for(int i=0; i<n; i++) { // 循环申请n个结点来接收a中的元素
node=(LNode *)malloc(sizeof(LNode)); // 创建新结点
node->data=a[i]; // 为新结点赋予数据
temp->next=node; // 将原尾结点的下一个结点指向新结点
temp=temp->next; // 指向终端结点,以便接收下一个结点
}
temp->next=NULL; // 所有元素已经填装完成,将终端结点置为NULL
}
头插法建立单链表的核心代码:
/* 使用头插法建立单链表,即新添加的元素添加到链表的头部 */
/* *&C指的是建立的单链表;a[]指的是批量添加的元素数组;n表示数组长度 */
void createListF(LNode *&C,int a[],int n) {
LNode *temp,*node;
// 创建带头节点的单链表
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
for(int i=0; i<n; i++) {
node=(LNode *)malloc(sizeof(LNode));// 新建结点
node->data=a[i];// 为新结点赋值
// 注意:下面两行不能交换位置,否则会进入死循环
node->next=temp->next; // node所指新结点的指针域next指向C的开始结点
temp->next=node; // 头结点的指针域next指向node,使得node成为新的开始结点
}
}
单链表的删除、查找操作
题目
查找链表C(带头结点)中是否存在一个值为x的结点,若存在,则删除该结点并返回1,否则返回0。
思路
(1)定义一个指针变量p,让它一直走到表尾,每遇到一个新结点,就检测其值是否为x,是则证明找到了,否则继续检测下一个结点。
(2)当找到值为x的结点后就删除该结点。
代码
#include <stdio.h>
#include <stdlib.h>
// 声明结构体
struct LNode {
int data;
struct LNode *next;
};
/* 创建一个单链表,由用户输入整型测试数据 */
/* 返回一个单链表 */
LNode * createList() {
LNode *head;
LNode *p1,*p2;
p1=p2=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
head=NULL;
int i=0;
while(p1->data!=0) { // 当用户在控制台输入0时结束循环
i+=1;
if(i==1) {
head=p1;
} else {
p2->next=p1;
}
p2=p1;
p1=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
}
p2->next=NULL;
return head;
}
/* 打印单链表 */
/* *list指的是要被打印输出的单链表 */
void printList(LNode *list) {
printf("\n");
while(list!=NULL) { // 循环单链表
printf("%ld\t",list->data); // 打印单链表中的data数据
list=list->next; // 遍历至下一个结点
}
printf("\n"); // 换行
}
/* 求单链表的表长的算法 */
/* *list指的是单链表 */
int length(LNode *list) {
LNode *temp=list;// 临时指针变量
int i=0; // 计数器,用来统计表长,初始长度为0
while(temp!=NULL) { // 循环条件,当单链表中结点不为NULL
temp=temp->next; // 指向下一个结点
i++; // 计数器加1
}
return i;
}
/* 按序号查找的算法:findKth */
/* num表示结点的序号(不是下标);*list指的是要进行查找操作的单链表 */
LNode * findKth(int num,LNode *list) {
LNode *temp=list;
int i=1;// 计数器,统计当前是第几个结点
while(temp!=NULL&&i<num) { // 循环遍历结点,判断链表是否为空并且计数器小于查找查找序号(退出while循环后,i==K)
i+=1; // 计数器加1
temp=temp->next; // 指向下一个结点
}
if(i==num) { // 判断是否查找到序号
return temp;// 返回查找到的结点
} else {
return NULL;
}
}
/* 按值查找算法:find */
/* data指要查找的data;*list指的是要在哪个链表中查询 */
LNode * find(int data,LNode *list) {
LNode *temp=list;
while(temp!=NULL&&temp->data!=data) { // 遍历循环,当temp->data=x时跳出循环,temp即为所求
temp=temp->next;
}
return temp;
}
/* 在单链表中插入新结点 */
/* data指的是要插入的数据;p指的是要插入的结点序号位置(不是下标);*list指的是要插入的单链表 */
LNode * insert(int data,int p,LNode *list) {
LNode *newNode,*priorNode;
/* 分情况讨论:(1)插入位置在首位;(2)插入位置不在首位 */
/* (1)插入位置在首位的情况 */
if(p==1) { // 如果要插入的位置是第一个结点
newNode=(LNode *)malloc(sizeof(LNode)); // 分配一个新结点
newNode->data=data; // 指定新结点的数据
newNode->next=list; // 指定新结点的下一个结点的地址(如果是插入在首位,那么下一个结点的地址就是链表list的第一个结点的地址)
return newNode; // 返回结点链表
}
/* (2)插入位置不在首位的情况 */
priorNode=findKth(p-1,list);// 获取要插入位置的前一个结点的信息,priorNode结点是用来临时保存查找的前一个结点的信息的
if(priorNode==NULL) { // 判断priorNode是否为NULL
return NULL;
} else {
newNode=(LNode *)malloc(sizeof(LNode)); // 分配一个新结点
newNode->data=data; // 指定新结点的数据
newNode->next=priorNode->next; // 插入结点的下一个结点的地址就是原前一个结点priorNode的下一个结点priorNode->next
priorNode->next=newNode;// 将原前一个结点priorNode的下一个结点地址指向新结点newNode
return list;// 返回插入成功单链表
}
}
/* 删除单链表中指定序号位置的结点 */
/* p指的是要删除结点的序号位置;*list指的是要执行删除操作的单链表 */
LNode * deleteNode(int p,LNode *list) {
LNode *temp,*priorNode;
/* 分情况讨论:(1)删除位置在首位;(2)删除位置不在首位 */
/* (1)删除位置在首位的情况 */
if(p==1) {
temp=list; // 临时保存第一个结点的地址
if(list==NULL) { // 判断要删除的第一个结点是否为NULL
return NULL;
} else {
list=list->next; // 将开始结点指向第一个结点的下一个结点,达到了删除的目的
}
free(temp); // 释放结点资源
return list; // 返回删除成功的单链表
}
/* (2)删除位置不在首位的情况 */
priorNode=findKth(p-1,list); // 获取要被删除结点的前一个结点
if(priorNode==NULL) { // 判断前一个结点是否存在
printf("第%d个结点不存在!",p-1);
return NULL; // 判断要被删除的结点是否存在
} else if(priorNode->next==NULL) {
printf("第%d个结点不存在!",p);
return NULL;
} else {
temp=priorNode->next; // 临时保存要删除的结点
priorNode->next=temp->next;// 将前一个结点priorNode的下一个结点的地址指向被删除结点的下一个结点
free(temp);// 释放结点资源
return list;
}
}
int main() {
/* [0.]创建初始测试单链表 */
LNode *list,*t1,*t2,*t3,*t4;
LNode *list2,*mergeList;
list=createList();// 创建测试链表
printList(list);// 打印单链表
/* [1.]单链表的表长 */
printf("\n[1.]%d\n",length(list));
/* [2.]按序号查找结点 */
t1=findKth(3,list); // 在list单链表中查找序号为3的结点
printf("\n[2.]%d\n",t1->data);// 打印输出该结点的数据data
/* [3.]按值查找结点 */
t2=find(2,list); // 在list单链表中查找data为2的结点
printf("\n[3.]%d\n",t2->data);// 打印输出该节点的数据data
/* [4.]插入新结点 */
t3=insert(99,3,list); // 在list单链表中的序号为3的位置插入data为99的结点
printList(t3); // 打印当前链表
/* [5.]删除结点 */
t4=deleteNode(4,list);// 删除list单链表中序号为4的结点
printList(t4);// 打印删除后的list
return 0;
}
测试结果
算法总结
求单链表的表长的思路是:
- 使用计数器统计有多少个有效的元素结点。
求单链表的表长的核心代码是:
/* 求单链表的表长的算法 */
/* *list指的是单链表 */
int length(LNode *list) {
LNode *temp=list;// 临时指针变量
int i=0; // 计数器,用来统计表长,初始长度为0
while(temp!=NULL) { // 循环条件,当单链表中结点不为NULL
temp=temp->next; // 指向下一个结点
i++; // 计数器加1
}
return i;
}
按序号查找操作的思路是:
- 通过一个计数器来对比是否等于所给序号
- 如果相等则返回当前的结点链表
按序号查找操作的核心代码是:
/* 按序号查找的算法:findKth */
/* num表示结点的序号(不是下标);*list指的是要进行查找操作的单链表 */
LNode * findKth(int num,LNode *list) {
LNode *temp=list;
int i=1;// 计数器,统计当前是第几个结点
while(temp!=NULL&&i<num) { // 循环遍历结点,判断链表是否为空并且计数器小于查找查找序号(退出while循环后,i==K)
i+=1; // 计数器加1
temp=temp->next; // 指向下一个结点
}
if(i==num) { // 判断是否查找到序号
return temp;// 返回查找到的结点
} else {
return NULL;
}
}
按值查找操作的思路是:
- 将要查找的值与链表中每个元素的结点的值相比较
- 如果相等则返回
按值查找操作的核心代码是:
/* 按值查找算法:find */
/* data指要查找的data;*list指的是要在哪个链表中查询 */
LNode * find(int data,LNode *list) {
LNode *temp=list;
while(temp!=NULL&&temp->data!=data) { // 遍历循环,当temp->data=x时跳出循环,temp即为所求
temp=temp->next;
}
return temp;
}
在单链表中插入新结点的思路是:
- 分情况讨论,插入位置是否在首位
- 如果在首位,则创建新结点,将新结点的下一个结点地址指向原链表的头结点,再返回新结点即可
- 如果不在首位,则获取插入位置的前一个位置的结点,然后创建新结点进行连接
在单链表中插入新结点的核心代码是:
/* 在单链表中插入新结点 */
/* data指的是要插入的数据;p指的是要插入的结点序号位置(不是下标);*list指的是要插入的单链表 */
LNode * insert(int data,int p,LNode *list) {
LNode *newNode,*priorNode;
/* 分情况讨论:(1)插入位置在首位;(2)插入位置不在首位 */
/* (1)插入位置在首位的情况 */
if(p==1) { // 如果要插入的位置是第一个结点
newNode=(LNode *)malloc(sizeof(LNode)); // 分配一个新结点
newNode->data=data; // 指定新结点的数据
newNode->next=list; // 指定新结点的下一个结点的地址(如果是插入在首位,那么下一个结点的地址就是链表list的第一个结点的地址)
return newNode; // 返回结点链表
}
/* (2)插入位置不在首位的情况 */
priorNode=findKth(p-1,list);// 获取要插入位置的前一个结点的信息,priorNode结点是用来临时保存查找的前一个结点的信息的
if(priorNode==NULL) { // 判断priorNode是否为NULL
return NULL;
} else {
newNode=(LNode *)malloc(sizeof(LNode)); // 分配一个新结点
newNode->data=data; // 指定新结点的数据
newNode->next=priorNode->next; // 插入结点的下一个结点的地址就是原前一个结点priorNode的下一个结点priorNode->next
priorNode->next=newNode;// 将原前一个结点priorNode的下一个结点地址指向新结点newNode
return list;// 返回插入成功单链表
}
}
删除单链表中指定序号位置结点操作的思路是:
- 也分情况讨论,删除位置是否是首位
- 如果是首位,则将头结点指向原头结点的下一个结点,然后使用free()是否资源。
- 如果不在首位,则通过findKth()方法获取要删除结点的前一个结点,然后更改结点的下一个结点指向
删除单链表中指定序号位置结点操作的核心代码是:
/* 删除单链表中指定序号位置的结点 */
/* p指的是要删除结点的序号位置;*list指的是要执行删除操作的单链表 */
LNode * deleteNode(int p,LNode *list) {
LNode *temp,*priorNode;
/* 分情况讨论:(1)删除位置在首位;(2)删除位置不在首位 */
/* (1)删除位置在首位的情况 */
if(p==1) {
temp=list; // 临时保存第一个结点的地址
if(list==NULL) { // 判断要删除的第一个结点是否为NULL
return NULL;
} else {
list=list->next; // 将开始结点指向第一个结点的下一个结点,达到了删除的目的
}
free(temp); // 释放结点资源
return list; // 返回删除成功的单链表
}
/* (2)删除位置不在首位的情况 */
priorNode=findKth(p-1,list); // 获取要被删除结点的前一个结点
if(priorNode==NULL) { // 判断前一个结点是否存在
printf("第%d个结点不存在!",p-1);
return NULL; // 判断要被删除的结点是否存在
} else if(priorNode->next==NULL) {
printf("第%d个结点不存在!",p);
return NULL;
} else {
temp=priorNode->next; // 临时保存要删除的结点
priorNode->next=temp->next;// 将前一个结点priorNode的下一个结点的地址指向被删除结点的下一个结点
free(temp);// 释放结点资源
return list;
}
}
单链表操作总结
思路
- 求单链表的表长的思路是:
- 使用计数器统计有多少个有效的元素结点。
- 按序号查找操作的思路是:
- 通过一个计数器来对比是否等于所给序号
- 如果相等则返回当前的结点链表
- 按值查找操作的思路是:
- 将要查找的值与链表中每个元素的结点的值相比较
- 如果相等则返回
- 在单链表中插入新结点的思路是:
- 分情况讨论,插入位置是否在首位
- 如果在首位,则创建新结点,将新结点的下一个结点地址指向原链表的头结点,再返回新结点即可
- 如果不在首位,则获取插入位置的前一个位置的结点,然后创建新结点进行连接
- 删除单链表中指定序号位置结点操作的思路是:
- 也分情况讨论,删除位置是否是首位
- 如果是首位,则将头结点指向原头结点的下一个结点,然后使用free()是否资源。
- 如果不在首位,则通过findKth()方法获取要删除结点的前一个结点,然后更改结点的下一个结点指向
代码
/* 归并递增:将两个递增单链表归并成一个递增单链表(不带头节点),返回合并后的递增单链表 */
/* *A指的是递增单链表A;*B指的是递增单链表B;*&C是带头结点的单链表 */
void * merge(LNode *A,LNode *B,LNode *&C) {
LNode *p;
LNode *q;
p=A;// 注意:这里A传入的是不带头节点的单链表,如果A是带头结点的单链表,那么这里应该是p=A->next
q=B;// 注意:这里B传入的是不带头节点的单链表,如果B是带头结点的单链表,那么这里应该是p=B->next
/* 创建一个带头节点的单链表start */
LNode *temp;
C=(LNode *)malloc(sizeof(LNode));// 创建一个带头节点的链表
C->next=NULL;// 设置头节点的下一个结点为NULL
temp=C;// 临时保存头节点,也是尾结点,参与下面的结点连接操作
// (temp既相当于链表的头节点,又相当于链表的尾结点,完成的链表就是head->next)
/* 创建一个带头节点的单链表end */
while(p!=NULL&&q!=NULL) { // 在同时满足p和q链表不为NULL的情况下循环
// 判断p链表中结点的数据是否小于等于q链表中的数据
if(p->data<=q->data) { // 如果p->data比q->data小于等于,那么
// 体现了尾插法的思想
temp->next=p; // 将临时头节点的下一个结点指向p
p=p->next;// 并且p指向下一个结点
temp=temp->next; // 并且temp也指向终端结点
} else { // 反之,如果大,那么将q链表中的该结点添加到temp尾
temp->next=q;
q=q->next;
temp=temp->next;
}
}
if(p!=NULL) { // 处理q链表已经全部插入到新链表,而p链表还剩下些结点,那么将这些结点链接到temp尾
temp->next=p;
}
if(q!=NULL) { // 同上
temp->next=q;
}
}
/* 归并递减:将两个递增单链表归并成一个递减的单链表,返回一个递减的单链表 */
/* *A指的是递增单链表A;*B指的是递增单链表B */
LNode * mergeDe(LNode *A,LNode *B) {
LNode *C,*temp,*p;
LNode *a=A,*b=B;
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
while(a!=NULL&&b!=NULL) {
if(a->data<=b->data) {
// 为什么需要使用临时结点p?因为p要作为插入的新结点使用又要指向终端结点,不能混合交叉使用,所以需要一个临时结点来保存
p=a; // 临时保存a结点,即新要插入到链表头部的新结点
a=a->next; // 到a的下一个结点
p->next=temp->next; // 头插法的经典使用
temp->next=p;
} else {
p=b;
b=b->next;
p->next=temp->next;
temp->next=p;
}
}
while(a!=NULL) {
p=a;
a=a->next;
p->next=temp->next;
temp->next=p;
}
while(b!=NULL) {
p=b;
b=b->next;
p->next=temp->next;
temp->next=p;
}
return C->next;
}
/* 使用尾插法建立单链表,即新添加的元素添加到链表的尾部 */
/* *&C指的是建立的单链表;a[]指的是批量添加的元素数组;n表示数组长度 */
void createListL(LNode *&C,int a[],int n) {
LNode *temp,*node;
// 创建一个带头节点的单链表
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
// 循环遍历数组,批量为链表插入数据
for(int i=0; i<n; i++) { // 循环申请n个结点来接收a中的元素
node=(LNode *)malloc(sizeof(LNode)); // 创建新结点
node->data=a[i]; // 为新结点赋予数据
temp->next=node; // 将原尾结点的下一个结点指向新结点
temp=temp->next; // 指向终端结点,以便接收下一个结点
}
temp->next=NULL; // 所有元素已经填装完成,将终端结点置为NULL
}
/* 使用头插法建立单链表,即新添加的元素添加到链表的头部 */
/* *&C指的是建立的单链表;a[]指的是批量添加的元素数组;n表示数组长度 */
void createListF(LNode *&C,int a[],int n) {
LNode *temp,*node;
// 创建带头节点的单链表
C=(LNode *)malloc(sizeof(LNode));
C->next=NULL;
temp=C;
for(int i=0; i<n; i++) {
node=(LNode *)malloc(sizeof(LNode));// 新建结点
node->data=a[i];// 为新结点赋值
// 注意:下面两行不能交换位置,否则会进入死循环
node->next=temp->next; // node所指新结点的指针域next指向C的开始结点
temp->next=node; // 头结点的指针域next指向node,使得node成为新的开始结点
}
}
/* 打印单链表 */
/* *list指的是要被打印输出的单链表 */
void printList(LNode *list) {
printf("\n");
while(list!=NULL) { // 循环单链表
printf("%ld\t",list->data); // 打印单链表中的data数据
list=list->next; // 遍历至下一个结点
}
printf("\n"); // 换行
}
/* 求单链表的表长的算法 */
/* *list指的是单链表 */
int length(LNode *list) {
LNode *temp=list;// 临时指针变量
int i=0; // 计数器,用来统计表长,初始长度为0
while(temp!=NULL) { // 循环条件,当单链表中结点不为NULL
temp=temp->next; // 指向下一个结点
i++; // 计数器加1
}
return i;
}
/* 按序号查找的算法:findKth */
/* num表示结点的序号(不是下标);*list指的是要进行查找操作的单链表 */
LNode * findKth(int num,LNode *list) {
LNode *temp=list;
int i=1;// 计数器,统计当前是第几个结点
while(temp!=NULL&&i<num) { // 循环遍历结点,判断链表是否为空并且计数器小于查找查找序号(退出while循环后,i==K)
i+=1; // 计数器加1
temp=temp->next; // 指向下一个结点
}
if(i==num) { // 判断是否查找到序号
return temp;// 返回查找到的结点
} else {
return NULL;
}
}
/* 按值查找算法:find */
/* data指要查找的data;*list指的是要在哪个链表中查询 */
LNode * find(int data,LNode *list) {
LNode *temp=list;
while(temp!=NULL&&temp->data!=data) { // 遍历循环,当temp->data=x时跳出循环,temp即为所求
temp=temp->next;
}
return temp;
}
/* 在单链表中插入新结点 */
/* data指的是要插入的数据;p指的是要插入的结点序号位置(不是下标);*list指的是要插入的单链表 */
LNode * insert(int data,int p,LNode *list) {
LNode *newNode,*priorNode;
/* 分情况讨论:(1)插入位置在首位;(2)插入位置不在首位 */
/* (1)插入位置在首位的情况 */
if(p==1) { // 如果要插入的位置是第一个结点
newNode=(LNode *)malloc(sizeof(LNode)); // 分配一个新结点
newNode->data=data; // 指定新结点的数据
newNode->next=list; // 指定新结点的下一个结点的地址(如果是插入在首位,那么下一个结点的地址就是链表list的第一个结点的地址)
return newNode; // 返回结点链表
}
/* (2)插入位置不在首位的情况 */
priorNode=findKth(p-1,list);// 获取要插入位置的前一个结点的信息,priorNode结点是用来临时保存查找的前一个结点的信息的
if(priorNode==NULL) { // 判断priorNode是否为NULL
return NULL;
} else {
newNode=(LNode *)malloc(sizeof(LNode)); // 分配一个新结点
newNode->data=data; // 指定新结点的数据
newNode->next=priorNode->next; // 插入结点的下一个结点的地址就是原前一个结点priorNode的下一个结点priorNode->next
priorNode->next=newNode;// 将原前一个结点priorNode的下一个结点地址指向新结点newNode
return list;// 返回插入成功单链表
}
}
/* 删除单链表中指定序号位置的结点 */
/* p指的是要删除结点的序号位置;*list指的是要执行删除操作的单链表 */
LNode * deleteNode(int p,LNode *list) {
LNode *temp,*priorNode;
/* 分情况讨论:(1)删除位置在首位;(2)删除位置不在首位 */
/* (1)删除位置在首位的情况 */
if(p==1) {
temp=list; // 临时保存第一个结点的地址
if(list==NULL) { // 判断要删除的第一个结点是否为NULL
return NULL;
} else {
list=list->next; // 将开始结点指向第一个结点的下一个结点,达到了删除的目的
}
free(temp); // 释放结点资源
return list; // 返回删除成功的单链表
}
/* (2)删除位置不在首位的情况 */
priorNode=findKth(p-1,list); // 获取要被删除结点的前一个结点
if(priorNode==NULL) { // 判断前一个结点是否存在
printf("第%d个结点不存在!",p-1);
return NULL; // 判断要被删除的结点是否存在
} else if(priorNode->next==NULL) {
printf("第%d个结点不存在!",p);
return NULL;
} else {
temp=priorNode->next; // 临时保存要删除的结点
priorNode->next=temp->next;// 将前一个结点priorNode的下一个结点的地址指向被删除结点的下一个结点
free(temp);// 释放结点资源
return list;
}
}