线性表链式表示和实现(C语言)(二)

简介: 线性表链式表示和实现(C语言)

10.删除线性表某一位置的元素


//删除线性表某一位置的元素StatusDeleteList_L(LinkList&L,intindex)
{
LinkListp,q;
p=L;           //将线性表的头结点赋值给pintcount=0;   //计数器while(p->next&&count<index-1){
p=p->next;
count++;            //此时p一直指向第count个结点     }
if(!(p->next) ||count>index-1){     //越界判断 printf("当前位置无法删除元素\n");
returnERROR;
    }
q=p->next;
p->next=q->next;
free(q);
q=NULL;
printf("当前位置元素已删除\n");
returnOK;
} 

删除某一结点的思路仍然是从头结点开始遍历找到要删除的结点的位置的前一个结点,此时p就是要删除结点位置的前一个结点。将p的后一个结点赋值给q,此时q就是要删除的结点,将q的下一个结点与p的下一个结点连接,释放q结点,完成删除操作。

11.求线性表某一元素的前驱


//求线性表某一元素的前驱 StatusPriorElem_L(LinkListL,intindex)
{
LinkListp;
intcount=0;       //count为计数器 p=L;
while(p->next&&count<index-1){       //寻找第index-1个结点 p=p->next;            //p一直指向第count个结点 count++;
    }
if(!(p->next) ||count>index-1){       //越界判断 printf("当前位置无法求该元素的前驱\n"); 
returnERROR;
    }
if(p!=L)            //如果要获取第一个元素的前驱,就是获取头结点数据域的值 printf("该元素的前驱为:%d\n",p->data);
elseprintf("该位置的前驱是头结点\n头结点的数据域中存储的值为:%d\n",p->data);
returnOK;
}

和删除结点的思路完全一致,只不过求前驱时不需要进行删除结点,在循环中控制循环条件使p在index - 1位置结束循环,此时p指向的就是第index的前驱,直接将p结点的数据域输出即可

12.求线性表某一元素的后继


//求线性表某一元素的后继 StatusNextElem_L(LinkListL,intindex)
{
LinkListp;
intcount=0;
p=L->next;
while(p&&count<index){        //不断遍历寻找第index之后的结点 p=p->next;      //p一直指向index-1的后一个结点 count++;
    }
//!p的目的是为了确保i不大于表长-1,count>index的目的是为了确保index不小于0 if(!p||count>index){          //越界判断printf("当前位置无法求该元素的后继\n"); 
returnERROR;
    }
printf("该元素的后继为:%d\n",p->data);
}

在声明LinkList类型变量p时将L的首元结点赋值给p,在循环中p一直指向第index的下一个结点,所以直接将p结点的数据域输出即可

13.打印线性表


//打印线性表StatusPrintList_L(LinkListL)
{
if(!L){            //如果线性表不存在,返回ERROR printf("线性表不存在,无法打印\n");
returnERROR;
    }
LinkListp;
p=L->next;    //将L的首元结点赋值给p ,为了不将头结点打印出来 while(p){
printf(" %d",p->data);   //将p结点的数据域输出 p=p->next;    //结点不断的向后移动     }
printf("\n");
returnOK;
}

打印单链表的思路也是进行对单链表的遍历,在遍历的过程中将每个结点的数据域中存储的值输出

运行结果演示:


为了方便演示,在这里为单链表一次赋值为1,2,3,4,5

构造一个空的头结点

image.png

赋值操作

image.png

判断此时线性表是否为空

image.png

获取单链表的长度

image.png

获取2号位置的元素

image.png

在3号位置插入520并打印单链表

image.png

image.png

获取此时单链表的长度

image.png

删除3号位置的元素并打印单链表

image.png

image.png

求3号位置元素的前驱和后继

image.png

image.png

重置单链表并获取长度以及判断是否为空表

image.png

image.png

image.png

销毁单链表并进行赋值和判断是否为空

image.png

image.png

image.png

以上便是线性表链式表示和实现,由于链表在空间的合理利用上和插入、删除是不需要移动等的优点,因此在很多场合下它是线性表的首选存储结构。然而,它也存在着实现某些基本操作的缺点,比如:求线性表长度时不如顺序存储结构…

源码:


#include<stdio.h>#include<stdlib.h>#include<malloc.h>#include<windows.h> //函数结果状态代码 #define TRUE     1     //代码中出现TRUE相当于出现了1 #define FALSE    0     //出现FALSE相当于出现了0 #define OK       1     //出现OK相当于出现了1 #define ERROR    0     //出现ERROR相当于出现了0 #define INFEASIBLE    -1#define OVERFLOW      -2 typedefintStatus;    //定义函数的返回状态 typedefintElemType; 
typedefstructLNode{
ElemTypedata;               //数据域 structLNode*next;          //指针域,指向一整个结点(结构体,该结构体中包含数据域和指针域) }LNode , *LinkList;        //* LinkList是结点的类型,在之后的代码中出现了它就相当于出现了指向这个结点的指针 //构造一个空的头结点 StatusInitList_L(LinkList&L){     //之前因为没有输入"&"符号,没有使用引用传递也就意味着没有开辟了新的内存空间,所以在之后赋值的时候会出现无法赋值的情况 L= (LinkList)malloc(sizeof(LNode));      //产生头结点,并使L指向该头结点(L也称头指针)if(!L)  returnERROR;          //如果存储空间分配失败,返回ERRORL->next=NULL;                //将指针域赋值为NULL,在这里要强调一点:"->"是一个整体,它是用于指向结构体子数据的指针 printf("空的头结点创建成功\n");
returnOK; 
} 
//对线性表进行赋值 StatusValueList_L(LinkList&L,ElemTypee){
LinkLists,p;
p=L;  
while(p->next){
p=p->next;
    }
s= (LinkList)malloc(sizeof(LNode));       //生成一个新结点 s->data=e;                 //将e赋值给新结点的数据域 s->next=p->next;           //将新结点与后一个结点的地址连接p->next=s;
returnOK; 
} 
//对线性表进行销毁StatusDistoryList_L(LinkList&L) {
/*从头结点开始逐一释放,释放前使p指向头结点,q指向开始释放的结点当开始结点不为空时,执行释放过程先释放头结点,然后将p,q都向后移,依次释放因为q始终是p的后继,所以最后一定是p留到最后,最后释放p*/if(!L){            //如果线性表不存在,返回ERROR printf("线性表不存在\n");
returnERROR;
    }
LinkListq=L->next;    //使q指向单链表的首元结点  while(q!=NULL){     //当q结点不为空时一直进入循环 free(L);          //释放L结点 L=q;            //将q结点赋值给L结点 q=L->next;      //将q结点赋值给L结点以后使q结点指向L的下一个结点     } 
free(L);    //此时q的值为NULL,L指向尾结点,将其释放L=NULL;   //free函数只是将之前动态分配给L的内存归还给系统,但是指针类型的结点L仍然存在//为了防止之后发生野指针访问,将L赋值为NULL printf("线性表已销毁\n"); 
}
//对线性表进行重置StatusClearList_L(LinkList&L)
{
if(!L->next){
printf("线性表为空表,不需要重置\n");
returnERROR;
    }
LinkListp,q;
p=L->next;          //将单链表的头结点赋值给pwhile(p){
q=p->next;      //将单链表的首元结点赋值给qfree(p);
p=q;
    } 
L->next=NULL;     //将头结点的指针域赋值为空 printf("线性表已重置\n");
returnOK;
} 
//判断线性表是否为空StatusListEmpty_L(LinkListL)
{
if(L){
if(L->next==NULL)       //如果首元结点不存在 printf("线性表是空表\n");
elseprintf("线性表不是空表\n");
    }
else{
printf("线性表不存在,无法判断\n");    
    }
returnOK;
} 
//获取线性表的长度StatusListLength_L(LinkListL,intcount)
{
//L为带头结点的单链表的头指针,count为计数器LinkListp=L->next;    //定义p为单链表L的指针域 while(p){
p=p->next;
count++;
    }
returncount;
}   
//获取线性表某一位置对应的元素StatusGetElem_L(LinkListL,intindex)
{
LinkListp;
p=L->next;       //使p指向L的首元结点intcount=1;    //count为计数器 ,赋值等于1的原因是从首元结点开始计数 while(p&&count<index){    //顺着指针向后查找,直到p指向第index个元素或p为空 p=p->next;
count++;        //此时p一直指向第count个元素     }
if(!p||count>index){
printf("当前位置没有元素\n");
returnERROR;
    }
printf("第%d个元素的值是:%d\n",index,p->data);
returnOK;
} 
//在线性表某一位置插入元素StatusListInsert_L(LinkList&L,intindex,ElemTypee)
{
LinkListp,q;
p=L;      //将线性表的头结点赋值给pintcount=0;    //count为计数器 while(p&&count<index-1){      //寻找第index-1个结点 p=p->next;         //此时的p结点指向第index-1个结点 count++; 
    }
if(!p||count>index-1){        //越界判断,index小于1或是index大于表长加1 printf("当前结点无法插入元素\n");
returnERROR;
    }
q= (LinkList)malloc(sizeof(LNode));
q->data=e;            //将e赋值到q的数据域当中q->next=p->next;
p->next=q;
printf("元素插入成功\n");
returnOK; 
}
//删除线性表某一位置的元素StatusDeleteList_L(LinkList&L,intindex)
{
LinkListp,q;
p=L;           //将线性表的头结点赋值给pintcount=0;   //计数器while(p->next&&count<index-1){
p=p->next;
count++;            //此时p一直指向第count个结点     }
if(!(p->next) ||count>index-1){     //越界判断 printf("当前位置无法删除元素\n");
returnERROR;
    }
q=p->next;
p->next=q->next;
free(q);
q=NULL;
printf("当前位置元素已删除\n");
returnOK;
} 
//求线性表某一元素的前驱 StatusPriorElem_L(LinkListL,intindex)
{
LinkListp;
intcount=0;       //count为计数器 p=L;
while(p->next&&count<index-1){       //寻找第index-1个结点 p=p->next;            //p一直指向第count个结点 count++;
    }
if(!(p->next) ||count>index-1){       //越界判断 printf("当前位置无法求该元素的前驱\n"); 
returnERROR;
    }
if(p!=L)            //如果要获取第一个元素的前驱,就是获取头结点数据域的值 printf("该元素的前驱为:%d\n",p->data);
elseprintf("该位置的前驱是头结点\n头结点的数据域中存储的值为:%d\n",p->data);
returnOK;
}
//求线性表某一元素的后继 StatusNextElem_L(LinkListL,intindex)
{
LinkListp;
intcount=0;
p=L->next;
while(p&&count<index){        //不断遍历寻找第index之后的结点 p=p->next;      //p一直指向index-1的后一个结点 count++;
    }
//!p的目的是为了确保i不大于表长-1,count>index的目的是为了确保index不小于0 if(!p||count>index){          //越界判断printf("当前位置无法求该元素的后继\n"); 
returnERROR;
    }
printf("该元素的后继为:%d\n",p->data);
}
//打印线性表StatusPrintList_L(LinkListL)
{
if(!L){            //如果线性表不存在,返回ERROR printf("线性表不存在,无法打印\n");
returnERROR;
    }
LinkListp;
p=L->next;    //将L的首元结点赋值给p ,为了不将头结点打印出来 while(p){
printf(" %d",p->data);   //将p结点的数据域输出 p=p->next;    //结点不断的向后移动     }
printf("\n");
returnOK;
}
intmain(){
SetConsoleTitle("Dream_飞翔");              //控制windows终端控制台的名称 //system("mode con cols=60 lines=30");        这条语句可以控制windows终端控制台的大小 LinkListL=NULL;               //声明线性表的头结点,但是并未进行初始化 intchoose,index,e,Num,Value,k;
while(1){
printf("*****************************************\n");
printf("*                                       *\n");
printf("*  线性表的链式表示和实现:             *\n");
printf("*                                       *\n");
printf("*    1.  构造一个空的头结点             *\n");
printf("*    2.  对线性表进行赋值               *\n");
printf("*    3.  对线性表进行销毁               *\n");
printf("*    4.  对线性表进行重置               *\n"); 
printf("*    5.  判断线性表是否为空             *\n");
printf("*    6.  获取线性表的长度               *\n");
printf("*    7.  获取线性表某一位置对应的元素   *\n");
printf("*    8.  在线性表某一位置插入元素       *\n");
printf("*    9.  删除线性表某一位置的元素       *\n");
printf("*    10. 求线性表某一元素的前驱         *\n");
printf("*    11. 求线性表某一元素的后继         *\n");
printf("*    12. 打印线性表                     *\n");
printf("*    13. 退出                           *\n");
printf("*                                       *\n");
printf("*****************************************\n");
printf("请做出您的选择:");
scanf("%d",&choose);
switch(choose){
case1:InitList_L(L);break;
case2:{
if(L){      //对线性表赋值的前提是线性表的头结点存在 printf("请输入线性表元素的个数:");
scanf("%d",&Num);
if(Num>0){
for(inti=1;i<=Num;i++){
printf("请输入第%d个元素的值:",i);
scanf("%d",&Value);
ValueList_L(L,Value);
                        }
printf("线性表赋值成功\n");
                    }
elseprintf("请输入一个有效数字\n");
                }
elseprintf("线性表不存在,无法赋值\n"); 
                }
break;
case3:DistoryList_L(L);break;
case4:ClearList_L(L);break;
case5:ListEmpty_L(L);break;
case6:{
intcount=ListLength_L(L,1);
printf("线性表的长度为:%d\n",count-1);
            };break;
case7:{ 
printf("请输入要获取元素的位置:");
scanf("%d",&index);
GetElem_L(L,index); 
            }
break;
case8:{
printf("请输入插入元素的位置:");
scanf("%d",&index);
printf("请输入插入元素的值:");
scanf("%d",&e);
ListInsert_L(L,index,e);
            }
break;
case9:{
printf("请输入要删除元素的位置:");
scanf("%d",&index);
DeleteList_L(L,index);
            }
break;
case10:{
if(L){
printf("请输入想要查找哪一个元素的前驱:");
scanf("%d",&index);
PriorElem_L(L,index);
                }
elseprintf("线性表不存在,无法获取其中元素的前驱\n");
            }
break;
case11:{
if(L){
printf("请输入想要查找哪一个元素的后继:");
scanf("%d",&index);
NextElem_L(L,index);
                }
elseprintf("线性表不存在,无法获取其中元素的后继\n");
            }
break; 
case12:PrintList_L(L);break;
case13:exit(0);
        }
    }
return0;
}
相关文章
|
7月前
|
C语言
基于链表实现的链式管理系统(C语言课设)
基于链表实现的链式管理系统(C语言课设)
|
7月前
|
存储 C语言
C语言线性表的链式表示和实现讲解
C语言线性表的链式表示和实现讲解
44 0
|
2月前
|
C语言
链式顺序表实现(C语言描述)
本文介绍了如何在C语言中实现链式顺序表,包括数据结构的定义、节点的创建、数据的插入和删除以及链表的打印和销毁。
49 2
|
程序员 编译器 C语言
【C语言】——函数的嵌套调用和链式访问
【C语言】——函数的嵌套调用和链式访问
【C语言】——函数的嵌套调用和链式访问
数据结构入门(C语言版)二叉树链式结构的实现
从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的。
|
存储 C语言 计算机视觉
二叉树的链式结构 - C语言(含有大量递归)上
二叉树的链式结构 - C语言(含有大量递归)
104 0
|
7月前
|
存储 C语言 索引
C语言线性表的顺序表示和实现讲解
C语言线性表的顺序表示和实现讲解
39 0
|
存储 C语言
数据结构 C语言 2.1 线性表抽象数据类型 2.2 小议顺序表
数据结构 C语言 2.1 线性表抽象数据类型 2.2 小议顺序表
51 0
|
C语言
C语言---函数知识点总结---函数的调用,嵌套调用和链式访问
C语言---函数知识点总结---函数的调用,嵌套调用和链式访问
|
C语言
【C语言】 函数(下):函数的嵌套调用 -- 链式访问 -- 声明 -- 定义 -- 递归 -- 练习3
【C语言】 函数(下):函数的嵌套调用 -- 链式访问 -- 声明 -- 定义 -- 递归 -- 练习3