博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构之单链表C语言实现,以及其中的常见的错误总结和修改
阅读量:2338 次
发布时间:2019-05-10

本文共 5117 字,大约阅读时间需要 17 分钟。

自己参考了一些书和网上的代码,然后总结了一下。附加一些自己在途中遇见的错误。可以运行,可以通过。

代码实现

#include 
#include
typedef enum {
false,true} Status;//定义节点类的数据域typedef struct{
char *name;}ElemType;//定义节点的构成:节点:数据域和指针域typedef struct Node{
ElemType data; //节点域 struct Node *Next; //指针域}Node;typedef struct Node *LinkList; //将指向结点结构体的指针命名为LinkList//定义相关的方法Status InitList(LinkList *L);Status ListAdd(LinkList L,ElemType e);void ShowList(LinkList L);Status ListInsert(LinkList L,int i,ElemType e);Status ListDeleteNo(LinkList L,int i);Status GetElem(LinkList L, int i,LinkList *e);int getlength(LinkList L);int main(){
printf("构造链表: \n"); LinkList test ; InitList(&test); ElemType one = {
"郭龙"}; ElemType two = {
"陈宁"}; ElemType three = {
"石翔旭"}; ElemType four = {
"许可"}; ElemType five = {
"庄钦"}; ElemType six = {
"刘沛沛"}; ListAdd(test,one); ListAdd(test,two); ListAdd(test,three); ListAdd(test,four); ListAdd(test,five); ListAdd(test,six); ShowList(test); printf("4号位插入节点: \n"); ElemType insert = {
"吴天爬"}; ListInsert(test,4,insert); ShowList(test); printf("6号删除结点:\n"); ListDeleteNo(test,6); ShowList(test); printf("查找3号结点,并将之删除返回 \n \n"); LinkList goal; GetElem(test,2,&goal); printf("查找的目标节点:%s \n\n",goal->data.name); printf("查找之后的链表: \n"); ShowList(test); printf("测试:获取链表的长度 \n \n"); int length = 0; printf("链表的长度为:%d \n",getlength(test)); ShowList(test); return 0;}/* 功能描述:初始化对应的链表,将传入的创建的链表进行初始化*/Status InitList(LinkList *L){
*L = (Node *)malloc(sizeof(Node)); //判定是否分配成功 if(*L == NULL) {
printf("申请空间失败"); return false; } //初始化的链表,没有一个元素,将头指针的next置为空 (*L)->Next = NULL; return true;}/* 功能描述:在链表L的末位增加新的结点*/Status ListAdd(LinkList L,ElemType e){
//根据传入的结点的值,申请空间组装成对应的结点 Node *temp; temp = (Node *)malloc(sizeof(Node)); if(temp == NULL) {
printf("分配失败"); return false; } temp->data = e; temp->Next = NULL; //遍历到链表的末位 while(L->Next) {
L = L->Next; } L->Next = temp; return true;}/* 功能描述:在第i个结点处插入以e为数据的新的结点*/Status ListInsert(LinkList L,int i,ElemType e){
//判定链表是否为空和输入是否合法 if(!L->Next ) {
printf("链表为空"); return false; } if(i < 1) {
printf("输入非法"); return false; } //遍历到对应的位置的前一个位置 LinkList p = NULL; p = L->Next; int j = 1; while(p && j < i - 1) {
p = p->Next; j ++; } //假设只有四个结点,要求插入的位置是第六个 if(!p ) {
return false; } //构造结点,尾指针为空 Node *temp = NULL; temp = (Node *)malloc(sizeof(Node)); if(!temp) {
printf("未申请到空间"); return false; } temp->data = e; temp->Next = NULL; //连接起对应的指针 temp->Next = p->Next; p->Next = temp; return true;}/* 功能描述:根据传入的索引,将节点删除*/Status ListDeleteNo(LinkList L,int i){
//判定链表是否为空 if(!L->Next || i < 1) {
return false; } //遍历到对应的结点的前一个结点 LinkList p = NULL; p = L->Next; int j = 1; while(p && j < i - 1) {
p = p->Next; j ++; } //判定特殊情况,如果输入的结点的序号大于拥有的结点数 if(!p) {
return false; } //删除结点 LinkList q = NULL; q = p->Next; p->Next = p->Next->Next; free(q); return true;}/* 功能描述:用e返回L中第i个数据元素的值 返回值:0,输入错误;1,查找成功*/Status GetElem(LinkList L,int i,LinkList *e){
//判定输入的索引是否正确 和链表是否为空 if(i < 1 || !L->Next) {
return false; } //遍历将p指向i对应结点 int j = 1; L = L->Next; while(L && j < i) {
L = L->Next; j ++; } //针对两种情况:查找越界,输入的索引大于有的结点数 if(!L) {
return false; } *e = L; //将地址传给主函数,造成结点被非法修改 return true;}/* 功能描述:获取链表的长度,将值返回给外部的参数*/int getlength(LinkList L){
int j = 0; L = L->Next; while(L) {
L = L->Next; j ++; } return j;}/* 功能描述:展示输出对应的链表*/void ShowList(LinkList L){
L = L->Next; int i = 1; while(L) {
printf(" 结点%3d:%5s \n",i,L->data.name); i ++; L = L->Next; } printf("*********************************************************** \n \n");}

运行效果

在这里插入图片描述

常见错误一:尾结点的Next指针并没有处理

在这里插入图片描述

在这里插入图片描述

  • 没有将加入的最后一个结点的指针域next置为NULL,陷入无限的死循环
常见的错误二:初始化函数InitList
/*    功能描述:初始化对应的链表,将传入的创建的链表进行初始化*/Status InitList(LinkList L){
L = (Node *)malloc(sizeof(Node)); //已经修改了形参指针的值,并不是修改实参的地址,已经和实参没有任何的关系 //判定是否分配成功 if(L == NULL) {
printf("申请空间失败"); return false; } //初始化的链表,没有一个元素,将头指针的next置为空 L->Next = NULL; return true;}
  • 错误分析:传入的是在主函数声明的指向结点的指针,但是在函数中自己又申请了新的地址,改变了形参的值。已经和主函数声明的指针没有任何关系。所以,并没有初始化成功。
  • 将指针当做链表本身,以为改了指针就是改了链表本身。实际形参的指针的值,并没有改变实参。
常见错误三:混淆指针和指针的指针的含义
  • 在主函数中将一个指针初始化为NULL,通过值传递,传递给函数。在函数中对形参进行解引用操作,指向的仍旧是NULL,即使对NULL进行赋值还是NULL。
  • 要想改变主函数中的指针值,应该调用主函数中指针的指针,通过指针的指针来改变主函数中指针的指向的具体的地址值。
  • 改正方法一:在主函数中构造一个具体的结构体,在函数中通过指针将主函数中的结构体值改变

在这里插入图片描述

  • 改正方法二:将函数的形参改为指针的指针,通过函数将链表对应的结点的地址传递给主函数的指针。
    • 问题:由于已经链表的结点的地址传递出来了,就有从外界非法改动链表的可能,所以不建议采用
    • 在这里插入图片描述
常见错误四:删除或者清空整个链表,没有的将对应的结点的内存释放

在这里插入图片描述

  • 删除结点或者清空整个链表,记得回收对应的空间。否则会造成内存泄露,可用的内存空间越来越少。

转载地址:http://lggpb.baihongyu.com/

你可能感兴趣的文章
Java虚拟机:类的初始化
查看>>
Oracle表连接方法 (上)
查看>>
谈mvc
查看>>
给年轻工程师的十大忠告!
查看>>
少走弯路的十条忠告
查看>>
未婚男子必读的31条感悟
查看>>
Proteus 使用虚拟串口
查看>>
使用软件虚拟串口
查看>>
MSComm 控件
查看>>
在VC6.0及VS中添加对话框oninitdialog()函数的方法
查看>>
用控件(CMSComm)串口调试问题的解决
查看>>
Windows CE下的串口通信编程
查看>>
串口通信学习(发送)
查看>>
全面剖析《自己动手写操作系统》的pmtest1.asm
查看>>
寻址方式介绍
查看>>
自己动手写操作系统--个人实践
查看>>
安装Gvim及问题解决
查看>>
SIM300-E GPRS模块硬件
查看>>
cadence16.3安装问题解决(解决最后的license的问题)
查看>>
什麽是世界上最值得珍惜的
查看>>