作者在学习数据结构时,发现鲜有完全按照 C 语言描述的算法操作,这让习惯于写 .c 而不是 .cpp 的初学者很是头疼。本文将基于 C 语言描述算法操作,如有错漏还望大佬们指正。
前言
本文将按照严惠敏所著《数据结构(C语言版)》所做的函数原型声明进行算法描述,由于C语言不支持函数参数中出现取地址符,我将函数参数更改为指针,调用函数时需要使用一级指针。新增了打印函数 PrintList; 顺序表的基本操作调用示例将在本文后给出。
一、顺序表基本操作的函数声明
//构造一个空的线性表 L
extern Status InitList(SqList *L);
//销毁线性表 L
extern Status Destroylist(SqList *L);
//将 L 重置为空表
extern Status ClearList(SqList *L);
//若 L 为空表,则返回 TRUE,否则返回 FALSE
extern Status ListEmpty(SqList L);
//返回 L 中数据元素个数
extern int ListLength(SqList L);
//用 e 返回 L 中第 i 个数据元素的值
extern Status GetElem(SqList L, int i, ElemType *e);
//返回 L 中第一个与 e 满足关系 compare() 的数据元素的位序,若这样的数据元素不存在,则返回 0
extern int LocateElem(SqList L, ElemType e, Status (*compare)(ElemType, ElemType));
//若 cur_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义
extern Status PriorElem(SqList L, ElemType cur_e, ElemType *pre_e);
//若 cur_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继,否则操作失败,next_e 无定义
extern Status NextElem(SqList L, ElemType cur_e, ElemType *next_e);
//在 L 中第 i (1 <= i <= ListLength(L) + 1) 个位置之前插入新的数据元素 e,L 的长度加 1
extern Status ListInsert(SqList *L, int i, ElemType e);
//删除 L 的第 i (1 <= i <= ListLength(L) + 1) 个数据元素,并用 e 返回其值,L 的长度减 1
extern Status ListDetele(SqList *L, int i, ElemType *e);
//打印线性表 L
extern Status PrintList(SqList L);
//将所有在线性表 Lb 中但不在 La 中的数据元素插入到 La 中
extern Status UnionList(SqList *La, SqList Lb);
//归并两个非递减排列的线性表 La、Lb 至 Lc,Lc也是非递减排列的
extern Status MergeList(SqList La, SqList Lb, SqList *Lc);
二、顺序表基本操作的完整描述
/* 顺序表 */
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
#define EQUAL 0
#define LOWER 1
#define HIGHER 2
typedef int Status;
typedef int ElemType;
typedef struct {
ElemType* elem; //存储空间基址
int length; //当前长度
int listsize;//当前分配的存储容量
} SqList;
//构造一个空的线性表 L
extern Status InitList(SqList* L);
//销毁线性表 L
extern Status Destroylist(SqList* L);
//将 L 重置为空表
extern Status ClearList(SqList* L);
//若 L 为空表,则返回 TRUE,否则返回 FALSE
extern int ListEmpty(SqList L);
//返回 L 中数据元素个数
extern int ListLength(SqList L);
//用 e 返回 L 中第 i 个数据元素的值
extern Status GetElem(SqList L, int i, ElemType* e);
//返回 L 中第一个与 e 满足关系 compare() 的数据元素的位序,若这样的数据元素不存在,则返回 0
extern int LocateElem(SqList L, ElemType e, Status(*compare)(ElemType, ElemType));
//若 cur_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义
extern Status PriorElem(SqList L, ElemType cur_e, ElemType* pre_e);
//若 cur_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继,否则操作失败,next_e 无定义
extern Status NextElem(SqList L, ElemType cur_e, ElemType* next_e);
//在 L 中第 i (1 <= i <= ListLength(L) + 1) 个位置之前插入新的数据元素 e,L 的长度加 1
extern Status ListInsert(SqList* L, int i, ElemType e);
//删除 L 的第 i (1 <= i <= ListLength(L) + 1) 个数据元素,并用 e 返回其值,L 的长度减 1
extern Status ListDetele(SqList* L, int i, ElemType* e);
//打印线性表 L
extern Status PrintList(SqList L);
//将所有在线性表 Lb 中但不在 La 中的数据元素插入到 La 中
extern Status UnionList(SqList* La, SqList Lb);
//归并两个非递减排列的线性表 La、Lb 至 Lc,Lc也是非递减排列的
extern Status MergeList(SqList La, SqList Lb, SqList* Lc);
Status InitList(SqList* L) {
L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));//存储分配失败
if (!L->elem) exit(OVERFLOW);
L->length = 0;
L->listsize = LIST_INIT_SIZE;
return OK;
}//InitList
Status Destroylist(SqList* L) {
free(L->elem);
L->elem = NULL;
L->length = 0;
L->listsize = 0;
return OK;
}//Destroylist
Status ClearList(SqList* L) {
free(L->elem);
L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if (!L->elem)
exit(OVERFLOW);
L->length = 0;
L->listsize = LIST_INIT_SIZE;
return OK;
}//ClearList
int ListEmpty(SqList L) {
return L.length == 0 ? TRUE : FALSE;
}//ListEmpty
int ListLength(SqList L) {
return L.length;
}//ListLength
Status GetElem(SqList L, int i, ElemType* e) {
if (i < 1 || i > L.length || L.length == 0)
return ERROR;
*e = L.elem[i - 1];
return OK;
}//GetElem
int LocateElem(SqList L, ElemType e, Status(*compare)(ElemType, ElemType)) {
int i = 1;
ElemType* p = L.elem;
while (i < L.length && !(*compare)(*p++, e)) ++i;
if (i <= L.length) return i;
else return 0;
}//LocateElem
Status PriorElem(SqList L, ElemType cur_e, ElemType* pre_e) {
ElemType* pre = L.elem;
for (ElemType* p = L.elem; p <= &(L.elem[L.length - 1]); p++) {
if (*p == cur_e) {
*pre_e = *pre;
return OK;
}
pre = p;
}
return ERROR;
}// PriorElem
Status NextElem(SqList L, ElemType cur_e, ElemType* next_e) {
ElemType* nxt = L.elem + 1;
for (ElemType* p = L.elem; p < &(L.elem[L.length - 1]); p++, nxt++) {
if (*p == cur_e) {
*next_e = *nxt;
return OK;
}
}
return ERROR;
}// NextElem
Status ListInsert(SqList* L, int i, ElemType e) {
if (i < 1 || i > L->length + 1) return ERROR;
if (L->length >= L->listsize) {
ElemType* newbase;
newbase = (ElemType*)realloc(L->elem, (L->listsize + LISTINCREMENT) * sizeof(ElemType));
if (!newbase) exit(OVERFLOW);
L->elem = newbase;
L->listsize += LISTINCREMENT;
}
ElemType* p, * q;
q = &(L->elem[i - 1]);
for (p = &(L->elem[L->length - 1]); p >= q; --p) *(p + 1) = *p;
*q = e;
++L->length;
return OK;
}// ListInsert
Status ListDetele(SqList* L, int i, ElemType* e) {
if (i < 1 || i > L->length) return ERROR;
ElemType* p, * q;
p = &(L->elem[i - 1]);
*e = *p;
q = L->elem + L->length - 1;
for (++p; p <= q; ++p) *(p - 1) = *p;
--L->length;
return OK;
}// ListDelete
Status ListTraverse(SqList L, void(*visit)(ElemType*)) {
ElemType* p;
int i;
p = L.elem;
for (i = 1; i <= L.length; i++)
visit(p++);
printf("\n");
return OK;
}// ListTraverse
Status PrintList(SqList L) {
ElemType e = 0;
for (int i = 1; i <= L.length; i++) {
GetElem(L, i, &e);
printf("%d ", e);
}
printf("\n");
return OK;
}// PrintList
Status UnionList(SqList* La, SqList Lb) {
int La_len, Lb_len;
ElemType e;
La_len = ListLength(*La); Lb_len = ListLength(Lb);
for (int i = 1; i < Lb_len; i++) {
GetElem(Lb, i, &e);
if (!LocateElem(*La, e, EQUAL))ListInsert(La, ++La_len, e);
}
}// UnionList
Status MergeList(SqList La, SqList Lb, SqList* Lc) {
InitList(Lc);
int i, j, k, La_len, Lb_len;
ElemType* a, * b;
a = (ElemType*)malloc(sizeof(ElemType));
b = (ElemType*)malloc(sizeof(ElemType));
i = j = 1; k = 0;
La_len = ListLength(La); Lb_len = ListLength(Lb);
while (i <= La_len && j <= Lb_len) {
GetElem(La, i, a + i); GetElem(Lb, j, b + j);
if (a[i] <= b[j]) { ListInsert(Lc, ++k, a[i]); ++i; }
else { ListInsert(Lc, ++k, b[j]); ++j; }
}
while (i <= La_len) {
GetElem(La, i++, a + i); ListInsert(Lc, ++k, a[i]);
}
while (j <= Lb_len) {
GetElem(Lb, j++, b + j); ListInsert(Lc, ++k, b[j]);
}
}// MergeList
三、调用示例
int main()
{
SqList L;
InitList(&L);
printf("ListEmpty: %d\n", ListEmpty(L));
ListInsert(&L, 1, 1);
ListInsert(&L, 2, 2);
ListInsert(&L, 3, 3);
ListInsert(&L, 4, 4);
ListInsert(&L, 5, 6);
PrintList(L);
return 0;
}
终端输出结果如下:
ListEmpty: 1
1 2 3 4 6
总结
以上是顺序表的基本操作的算法描述,更多数据结构的算法描述还在更新中,敬请关注作者专栏。