C语言抽象链表数据类型(抽象链表库)
抽象链表数据类型设计
- 利用C语言实现抽象数据类型的办法C语言实现抽象数据类型(ADT),实现抽象链表类型。
- 抽象链表,首先是链表,该抽象链表库实现链表结点的追加、删除、查找、遍历等功能。
- 该链表结构有指向表头、表尾的指针:
- 抽象链表指的是,希望建立一个通用的链表数据类型,可以用来创建存储整型,或是浮点型,或是“学生Student类型”,甚至是目前还没有实现的数据结构。该链表就像一个筐,一个容器,什么都能往里装,只要这个链表的方法实现一次,就能适用于多种数据类型,它不依赖所存储的具体数据类型,容器和容器中容纳的数据对象完全独立,这就是“泛型”,这可以减少重复代码的编写。
- C语言实现泛型的方法比较捉襟见肘。最常见的是用
void *
作为要存储的数据项类型。
typedef void * ADT; typedef const void * CADT;
,因为指向任何数据类型的指针,都可以赋值给void *
类型,void *
类型便可以“代表一切”。
使用void *作为数据项类型有两个缺点:1. 不适用于无法用指针形式表示的数据。数据项可以是字符串(用指向字符串的第一个字符的指针表示)或动态分配的结构体(如 struct Student *),但不能是int,double之类的基本类型。2. 不能进行错误检测,存放void *数据项的链表允许各种类型的指针共存,所以无法检测出由追加进存储不一致数据项类型的结点导致的错误。 - 利用
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-