链表可以加深我们对指针、结构体的理解。
我发现了一个问题,书中的代码不完全是c语言的代码,因为c语言没有引用,所以我便对书中代码加以修改。
欢迎各位大佬指点。
话不多说,上代码:
/*
本章节疑问:为什么链表要使用结构体指针变量?
(1)指针节省内存主要体现在参数传递上,比如传递一个结构体指针变量和传递一个结构体变量,
结构体占用内存越大,传递指针变量越节省内存的,也就是可以减少不必要的数据复制。
(2)C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等。
*/
/*------------------------线性表的单向单链表操作集-------------------------*/
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define OK 1 //返回值
#define ERROR 0
#define VOERFLOW -1
typedef int Elemtype; //数据类型
typedef int Status; //返回值类型
void test1(); //测试代码
void test2();
void test3();
void test4();
//单链表结构体
typedef struct LNode{
Elemtype data; //链表的数据域
struct LNode *next; //链表的指针域
}LNode,*LinkList; //结构体变量名,结构体指针变量名
//查找链表中对应的元素
Status GetElem_L(LinkList L,int i,Elemtype *e){
//L为带头结点的单链表的头指针
//当第i各元素存在时,将其值赋给e并返回OK,否则则返回ERROR
//初始化
LinkList p;
int c=1; //计数器
p=L->next; //p指向第一各结点
//查找i是否存在
while(p&&c<i){ //顺时针查找,直到p指向第i各元素或p为空
p=p->next;
++c;
}
if(!p||c>i){ //第i各元素不存在
return ERROR;
}
//存在则赋值
*e=p->data; //将第i个结点的数据域的值赋给e
return OK;
}
//往链表的指定位置插入一个元素
Status ListInsert_L(LinkList L,int i,Elemtype e){
//在带头结点的单链线性表L中第i个位置之前插入元素e
//初始化
LinkList p,tem;
int c=0;
p=L;
//查找到第i-1个结点
while (p&&c<i-1){
p=p->next;
++c;
}
//判断i是否存在
if(!p||c>i-1){ //i小于1或者大于表长加1
return ERROR;
}
//插入操作
tem=(LinkList)malloc(sizeof(LNode));//申请新结点
tem->data=e;
tem->next=p->next; //有先后顺序,先后再前
p->next=tem;
return OK;
}
//删除链表中指定位置的元素
Status ListDele_L(LinkList L,int i,Elemtype *e){
//在带头结点的单链表L中,删除第i个元素,并由e带出
//初始化
int c=0;
LinkList q,p;
p=L;
//查找第i个元素,并且让p指向其前驱
while(p->next&&c<i-1){
p=p->next;
++c;
}
//判断后面是否还有元素和i是否存在
if(!(p->next)||c>i-1){
return ERROR;
}
//将要删除的元素赋给q,再释放q
q=p->next; //无先后顺序
p->next=q->next;
free(q); //释放q,防止内存泄漏
return OK;
}
//逆序输入链表元素
Status ListCreate_FL(LinkList L,int n){
//逆序位输入n个元素的值,建立带表头结点的单链表L
//定义一个中间变量p、q,p用于存储新输入结点的元素,q用于操作之后赋给L,再由L带出
//初始化
LinkList p;
int i=0;
L->next=NULL; //使头节点的next为空,否则会出现下方逆序代码的q->next的地址不同
//输入和逆序操作
for(i=n;i>0;--i){
p=(LinkList)malloc(sizeof(LNode));//输入
scanf("%d",&(p->data));
p->next=L->next; //逆序,先后再前
L->next=p;
}
return OK;
}
//顺序输入链表元素
Status ListCreate_L(LinkList L,int n){
//顺序位输入n个元素的值,建立带表头结点的带单链表L
//定义一个中间变量p、q,p用于存储新输入结点的元素,q用于操作之后赋给L,再由L带出
//与逆序代码相似,变换了后面交换的代码
//初始化
LinkList p;
int i;
L->next=NULL;
//输入并且按顺序插入
for(i=n;i>0;--i){
p=(LinkList)malloc(sizeof(LNode));//输入
scanf("%d",&(p->data));
p->next=NULL; //顺序插入
L->next=p;
L=L->next; //结点后移一位
}
return OK;
}
//将两个有序的链表合并成一个
Status ListMerge_L(LinkList La,LinkList Lb,LinkList Lc){
//已知单链表La和Lb有序且按值非递见排序
//归并La和Lb得到新单链线性表Lc,Lc的元素也按非递减排列
//初始化
LinkList pa,pb,pc;
pa=La->next;
pb=Lb->next;
pc=Lc;
//归并排序
while(pa&&pb){
if(pa->data<=pb->data){ //比较两个链表里面元素的大小
pc->next=pa; //把pa赋给pc
pc=pc->next; //pc指针往后移
pa=pa->next; //pa指针往后移
}else{
pc->next=pb;
pc=pc->next;
pb=pb->next;
}
}
while(pa){ //插入剩余段
pc->next=pa;
pc=pc->next;
pa=pa->next;
}
while(pb){
pc->next=pb;
pc=pc->next;
pb=pb->next;
}
free(Lb); //释放Lb的头节点
free(La); //释放La的头节点
return OK;
}
int main(void){
test4();
system("pause"); //使运行结果在终端输出
return 0;
}
void test1(){
LinkList p;
int e;
p=(LinkList)malloc(sizeof(LNode));
if(ListInsert_L(p,1,11))
printf("OK\n");
else printf("ERROR\n");
if(GetElem_L(p,1,&e))
printf("%d\n",e);
else printf("ERROR\n");
if(ListDele_L(p,1,&e))
printf("%d\n",e);
}
void test2(){
LinkList p;
int i=0;
p=(LinkList)malloc(sizeof(LNode));
if(ListCreate_FL(p,3)){
printf("OK\n");
}
for(i;i<3;++i){
p=p->next;
printf("%d ",p->data);
}
}
void test3(){
LinkList p;
p=(LinkList)malloc(sizeof(LNode)); //在传入前需要开辟空间
//使用前需要先用head记录头结点的位置,因为ListCreat_L函数操作之后指针会指向最后一个结点
LinkList head=p;
int i=0;
if(ListCreate_L(p,3)){
printf("OK\n");
}
p=head;
for(i=0;i<3;++i){
p=p->next;
printf("%d ",p->data);
}
}
void test4(){
int i=0;
LinkList p1;
p1=(LinkList)malloc(sizeof(LNode));
if(ListCreate_FL(p1,3)){
printf("OK\n");
}
LinkList p2;
p2=(LinkList)malloc(sizeof(LNode));
if(ListCreate_FL(p2,3)){
printf("OK\n");
}
LinkList p3;
p3=(LinkList)malloc(sizeof(LNode));
if(ListMerge_L(p1,p2,p3)){
printf("OK\n");
}
for(i=0;i<6;i++){
p3=p3->next;
printf("%d ",p3->data);
}
}
使用vscode的方式在我第一个代码笔记中,这里我就不演示了。
接下来上运行结果:
测试代码1(插入。获取、删除操作):
测试代码2(逆序输出测试):
测试代码3(顺序输出测试):
测试代码4(合并代码测试):