C语言抽象链表数据类型(抽象链表库)

本文介绍了如何使用C语言实现抽象链表数据类型,包括链表的追加、删除、查找和遍历功能。通过使用void *作为数据项类型,实现了通用链表容器,能够存储不同类型的数据。然而,这种方法存在错误检测和类型限制的问题。文章还讨论了在处理基本类型和结构体时的注意事项,并给出了Point数据类型的示例。在实际应用中,需要通过回调函数和函数指针来处理数据类型的特定操作。最后,文章提到了测试程序及其运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


抽象链表数据类型设计

  1. 利用C语言实现抽象数据类型的办法C语言实现抽象数据类型(ADT),实现抽象链表类型。
  2. 抽象链表,首先是链表,该抽象链表库实现链表结点的追加、删除、查找、遍历等功能。
  3. 该链表结构有指向表头、表尾的指针:
    在这里插入图片描述
  4. 抽象链表指的是,希望建立一个通用的链表数据类型,可以用来创建存储整型,或是浮点型,或是“学生Student类型”,甚至是目前还没有实现的数据结构。该链表就像一个筐,一个容器,什么都能往里装,只要这个链表的方法实现一次,就能适用于多种数据类型,它不依赖所存储的具体数据类型,容器和容器中容纳的数据对象完全独立,这就是“泛型”,这可以减少重复代码的编写。
  5. C语言实现泛型的方法比较捉襟见肘。最常见的是用void *作为要存储的数据项类型。
    typedef void * ADT; typedef const void * CADT;,因为指向任何数据类型的指针,都可以赋值给void *类型,void *类型便可以“代表一切”。
    使用void *作为数据项类型有两个缺点:1. 不适用于无法用指针形式表示的数据。数据项可以是字符串(用指向字符串的第一个字符的指针表示)或动态分配的结构体(如 struct Student *),但不能是int,double之类的基本类型。2. 不能进行错误检测,存放void *数据项的链表允许各种类型的指针共存,所以无法检测出由追加进存储不一致数据项类型的结点导致的错误。
  6. 利用void *可以表示要存储的数据类型,关于对数据类型要进行的操作,比如遍历一遍链表,将里面存放的所有整形变量全都自增1;遍历一遍链表,将里面存放的学生数据对象的成绩全都改成不及格,这些操作就要通过回调函数函数指针来实现,就像学习函数指针时候一定会学到的qsort函数的例子展示的那样。

抽象链表类型的实现

dynlist.h

#ifndef DYNLIST_H
#define DYNLIST_H

typedef struct LIST * PLIST;

typedef void * ADT;
typedef const void * CADT;
typedef int (*COMPARE_OBJECT)(CADT e1, CADT e2);//用来比较ADT类型数据的回调函数的函数指针
typedef void (*DESTROY_OBJECT)(ADT e);//用来删除ADT数据类型的回调函数的函数指针
typedef void (*MANIPULATE_OBJECT)(ADT e, ADT tag);//用来操作ADT类型数据的回调函数的函数指针

PLIST LICreate();//链表的构造
void LIDestroy(PLIST list, DESTROY_OBJECT destroy);//链表的销毁
void LIAppend(PLIST list, ADT object);//追加节点
void LIInsert(PLIST list, ADT object, int pos);//插入节点
void LIDelete(PLIST list, int pos, DESTROY_OBJECT destroy);//删除节点
void LIClear(PLIST list, DESTROY_OBJECT destroy);//链表清空
void LITraverse(PLIST list, MANIPULATE_OBJECT manipulate, ADT tag);//链表遍历
bool LISearch(PLIST list, ADT object, COMPARE_OBJECT compare);//查找节点
int LIGetCount(PLIST list);//统计节点个数
bool LIIsEmpty(PLIST list);//链表是否为空

#endif

dynlist.cpp

#include <iostream>
#include <cstdio>
#include "dynlist.h"

using namespace std;

typedef struct NODE * PNODE;

struct NODE {
   
    ADT data;
    PNODE next;
};

struct LIST {
   
    int count; //节点个数
    PNODE head, tail;//链表头尾指针
};

PLIST LICreate()
{
   
    PLIST p = new LIST;
    p->count = 0;
    p->head = NULL;
    p->tail = NULL;
    return p;
}

void LIDestroy(PLIST list, DESTROY_OBJECT destroy)
{
   
    if (list) {
   
        LIClear(list, destroy);
        delete list;
    }
}

void LIAppend(PLIST list, ADT object)
{
   
    PNODE t = new NODE;
    if (!list || !object) {
   
        printf("LIAppend:参数非法!\n");
        exit(1);
    }
    t->data = object;
    t->next = NULL;
    if (!list->head) {
   //链表为空时,追加节点作为链表唯一节点
        list->head = t;
        list->tail = t;
    }
    else {
   //一般情况,把当前尾节点指向新节点,再将新节点作为新尾节点
        list->tail->next = t;
        list-
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值