第二章 2.7 纯链表的代码实践

在2.6节阐述了纯链表的理论思想后,我们可以模仿链式数组表的代码编写方式,编写完整的可执行的链表程序。

为了简化编程模型,假设我们要处理的数据元素为整型,数据来源为键盘输入,添加main()函数,以及输入输出函数,按照软件函数化(模块化)方法设计。

首先,我们构造出元素结点与头结点:

#include <stdio.h>
#include <stdlib.h>      //malloc,free需要
#include <time.h>
#include <stdbool.h>


struct node           //构建元素结点
{
 int data;
 struct node *next;    
};


struct list          //构建左边头结点
{
 int curr_length;      //表长
 char *create_date;    //表创建时间
 struct node *next;    //指向第一个元素位置
};
构造初始化函数initlist():

struct list *  initlist (void);        //返回值是指向头结点的指针

struct list * initlist(void)     
{
 struct list *L = (struct list *)malloc(sizeof(struct list)); //动态分配
 if (L==NULL)
    printf("\n初始化失败!!\n");
 L->curr_length =0;                 //初始化空表信息
 L->create_date =__DATE__;   
 L->next = NULL; 
return L;                                    //返回分配好的指针
}
和链式数组表不同,无论是信息结构体的创建,还是元素部分的创建,不在代码中显式写出,而是通过动态分配完成,尽管显式写出在功能上没有差别,但违背了链表动态创建的最大特色。

销毁函数destroylist():

void  destroylist(struct list *L);

void  destroylist(struct list *L)
{
  free(L);
}
该函数尚未完成,仅仅释放掉了头结点,而没有释放掉元素部分。


纯链表大概形态如图所示。

因为代码中需要大量使用struct结构体类型,我们可以引入typedef进行简化声明.

typedef struct node   NODE;
typedef struct node*  PTONODE;
typedef struct list   LIST;
typedef struct list*  PTOLIST;
改写后的完整程序如下:

<pre name="code" class="cpp">#include <stdio.h>
#include <stdlib.h>      //malloc,free需要
#include <time.h>
#include <stdbool.h>


struct node           //构建元素结点
{
 int data;
 struct node *next;    
};


struct list          //构建左边头结点
{
 int curr_length;      //表长
 char *create_date;    //表创建时间
 struct node *next;    //指向第一个元素位置
};


typedef struct node  NODE;
typedef struct node* PTONODE;
typedef struct list  LIST;
typedef struct list* PTOLIST;


//函数声明
PTOLIST  initlist (void);        //返回值是指向头结点的指针
void  destroylist(PTOLIST L);

//函数声明结束

//主程序开始:
int main()
{
 PTOLIST L = initlist();
 destroylist(L);
 return 0;
}
//主程序结束


//函数实现部分:

//初始化
PTOLIST  initlist(void)      
{
 PTOLIST L = (PTOLIST)malloc(sizeof(LIST)); //动态分配
 if (L==NULL)
    printf("\n初始化失败!!\n");
 L->curr_length =0;                 //初始化空表信息
 L->create_date =__DATE__;   
 L->next = NULL; 
return L;                                    //返回分配好的指针
}

//销毁表
void  destroylist(PTOLIST L)
{
  free(L);
}

 
从键盘读入数据时,只能在表尾处插入,才能保证数据的顺序不变。 

insertend(),注意细节:

//函数声明
bool  insertend(PTOLIST L, int e);
//函数声明结束


//表尾插入
bool insertend(PTOLIST L, int e)
{
 PTONODE new_unit = (PTONODE)malloc(sizeof(NODE));
 if (new_unit == NULL)
     {
      printf("\n分配新元素空间失败!\n");
      return 0;
     }
 PTONODE p = L->next;
 
  
  if (L->next  == NULL)           //细节:空表第一个元素插入时有区别
      L->next = new_unit;
  else           
    { 
      while (p->next != NULL)         //循环找出最后一个元素位置
           p = p->next;
      p->next = new_unit;
    } 
  new_unit->data  = e;     //插入表尾
  new_unit->next = NULL;
  ++ L->curr_length;       //更新表长
  return 1;
}  

删除表中所有元素时,既可以从表尾处开始,也可以从表头第一个元素开始,通过分析得知,从第一个元素开始删除效率最高deletefirst(),在此基础上还能构建出重置空表clearlilst():

//函数声明
void  deletefirst(PTOLIST L);
void  clearlist(PTOLIST L);

//函数声明结束


//函数实现部分:

//表头删除
void deletefirst(PTOLIST L)
{
 PTONODE p = L->next;
 L->next = p->next;
 free(p);
 -- L->curr_length;
}

//重置空表
void clearlist(PTOLIST L)
{
  while (L->next != NULL)
   deletefirst(L);
}
此时可以完善销毁表destroylist函数了,理念是先删除所有元素,再删除表头:

void  destroylist(PTOLIST L)
{
  clearlist(L);
  free(L);
}
添加遍历visitlist(),和查看表信息infolist()功能:

//函数声明
bool  visitlist(PTOLIST L);
void  infolist(PTOLIST L);
//函数声明结束


//主程序开始:
int main()
{
 PTOLIST L = initlist();
 printf("\n请输入整型数据,互相之间以回车或空格隔开:\n");
 printf("输入完成后按回车,再按ctrl+d结束:\n");
 
 int num;                        //存放scanf返回值
 char nouse[30];                 //30个字节的无用区
 int e;                          //输入值临时存放在e中


 while ((num= scanf ("%d",&e)) != EOF )
     {
       if (num == 0) {scanf("%s", nouse); continue; }    //非数值则放进无用区,跳过
       insertend(L,e);
     
      }
 infolist(L);
 visitlist(L);
 printf("\n开始重置空表\n");
 clearlist(L);
 infolist(L);
 visitlist(L);
 destroylist(L);
 return 0;
}
//主程序结束


//函数实现部分:

//遍历表
bool visitlist(PTOLIST L)
{
  PTONODE p = L->next;
  if (p == NULL) 
   {
    printf("\n数据表为空,请添加数据\n");
    return 0;
   } 
  printf("\n链表中的数据如下:\n");
  while ( p->next !=NULL)                //小细节:为空说明是最尾元素了。
    { printf("%d ", p->data);
      p = p-> next;
    }
   printf("%d \n", p->data);            //要单独显示
  return 1;
}

//查看表信息
void infolist (PTOLIST L)
{
   printf("\n表中现有元素:%d个\n",L->curr_length);
   printf("表创建时间为:%s\n", L->create_date);
}

运行结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值