C语言实现线性表的顺序存储及基本操作【线性表】(4)

ElemType.h

/***
*ElemType.h - ElemType的定义
*
****/

#ifndef ELEMTYPE_H
#define ELEMTYPE_H

typedef int ElemType;		//定义数据类型

int  compare(ElemType x, ElemType y);	//声明判断函数
void visit(ElemType e);					//声明打印函数

#endif /* ELEMTYPE_H */

DynaSeqList.h

/***
*
DynaSeqList.h - 动态顺序表的定义
*	
****/

#if !defined(DYNASEQLIST_H)
#define DYNASEQLIST_H

#include "ElemType.h"

/*------------------------------------------------------------
顺序表结构的定义
------------------------------------------------------------*/

typedef struct List
{
	ElemType *elem;				// 存储空间的基址
	int length;					// 顺序表中结点元素的个数
	int listsize;				// 顺序表的存储空间大小
} SqList;

/*------------------------------------------------------------
// 顺序表的基本操作
------------------------------------------------------------*/

bool InitList(SqList *L);			//线性表初始化
void DestroyList(SqList *L);		//线性表销毁
bool ListEmpty(SqList L);			//线性表判空
int  ListLength(SqList L);			//线性表长度
bool GetElem(SqList L, int i, ElemType *e);		//获得下标 i 的数据元素
int  LocateElem(SqList L, ElemType e, int (*fp)(ElemType, ElemType));//获得和元素e有关的元素
bool PriorElem(SqList L, ElemType cur_e, ElemType *pre_e);		//获得数据元素的前驱
bool NextElem(SqList L, ElemType cur_e, ElemType *nxt_e);		//获得数据元素的后继
void ListTraverse(SqList L, void (*fp)(ElemType));				//遍历线性表
void ClearList(SqList *L);										//清空线性表
bool ListInsert(SqList* L, int i, ElemType e);					//在 i 位置插入数据元素
void HeadInsert(SqList* L, ElemType e);							//线性表的头部插入元素
void TailInsert(SqList* L, ElemType e);							//线性表的尾部插入元素
bool ListDelete(SqList *L, int i, ElemType *e);					//删除 i 位置的数据元素
void ListDeleteHead(SqList* L,ElemType* e);						//删除线性表的头部元素
void ListDeleteTail(SqList* L,ElemType* e);						//删除线性表的尾部元素
void unionList(SqList* La, SqList Lb);							//求两个线性表的并集
#endif /* DYNASEQLIST_H */

DynaSeqList.cpp

/***
*DynaSeqList.cpp - 动态顺序表,即顺序表的动态数组实现
****/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#include "DynaSeqList.h"

const int LIST_INIT_SIZE = 100;	// 表初始分配的最大长度
const int LISTINCREMENT  = 10;	// 分配内存的增量

/*------------------------------------------------------------
操作目的:	初始化顺序表
初始条件:	无
操作结果:	构造一个空的线性表
函数参数:
		SqList *L	待初始化的线性表
返回值:
		bool		操作是否成功
------------------------------------------------------------*/
bool InitList(SqList *L)
{
	L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
	if (!L->elem)
		return false;
	else
	{
		L->length = 0;
		L->listsize = LIST_INIT_SIZE;
		return true;
	}
}

/*------------------------------------------------------------
操作目的:	销毁顺序表
初始条件:	线性表L已存在
操作结果:	销毁线性表L
函数参数:
		SqList *L	待销毁的线性表
返回值:
		无
------------------------------------------------------------*/
void DestroyList(SqList *L)
{
	if (L->elem)
		free(L->elem);
	L->elem = NULL;
}

/*------------------------------------------------------------
操作目的:	判断顺序表是否为空
初始条件:	线性表L已存在
操作结果:	若L为空表,则返回true,否则返回false
函数参数:
		SqList L	待判断的线性表
返回值:
		bool		是否为空
------------------------------------------------------------*/
bool ListEmpty(SqList L)
{
	if (!L.length)
		return true;
	else
		return false;
}

/*------------------------------------------------------------
操作目的:	得到顺序表的长度
初始条件:	线性表L已存在
操作结果:	返回L中数据元素的个数
函数参数:
		SqList L	线性表L
返回值:
		int			数据元素的个数
------------------------------------------------------------*/
int ListLength(SqList L)
{
	return L.length;
}

/*------------------------------------------------------------
操作目的:	得到顺序表的第i个元素
初始条件:	线性表L已存在,1<=i<=ListLength(L)
操作结果:	用e返回L中第i个数据元素的值
函数参数:
		SqList L	线性表L
		int i		数据元素的位置
		ElemType *e	第i个数据元素的值
返回值:
		bool		操作是否成功
------------------------------------------------------------*/
bool GetElem(SqList L, int i, ElemType *e)
{
	if (i < 1 || i > L.length)
		return false;
	else
		*e = L.elem[i - 1];
	return true;
}

/*------------------------------------------------------------
操作目的:	得到顺序表指定元素的位置
初始条件:	线性表L已存在
操作结果:	返回L中第一个与e满足关系compare()的数据元素的位序。
			若这样的元素不存在则返回0。
函数参数:
		SqList L	线性表L
		ElemType e	数据元素e
		int (*fp)()	用于比较相等的函数指针
返回值:
		int			与e满足关系compare()的数据元素的位序
------------------------------------------------------------*/
int LocateElem(SqList L, ElemType e, int (*fp)(ElemType, ElemType))
{
	for (int i = 0; i < L.length; i++)
	{
		if(!(*fp)(e,L.elem[i]))
			return i + 1;
	}
	return 0;
}

/*------------------------------------------------------------
操作目的:	得到顺序表指定元素的前驱
初始条件:	线性表L已存在
操作结果:	若cur_e是L的数据元素,且不是第一个,则用pre_e返回
			它的前驱,否则操作失败,pre_e无定义
函数参数:
		SqList L		线性表L
		ElemType cur_e	数据元素cur_e
		ElemType *pre_e	前驱数据元素
返回值:
		bool			操作是否成功
------------------------------------------------------------*/
bool PriorElem(SqList L, ElemType cur_e, ElemType *pre_e)
{
	int i = LocateElem(L, cur_e, compare);
	if (i!=0 && i!= 1)
	{
		*pre_e = L.elem[i - 2];
		return true;
	}
	return false;
}

/*------------------------------------------------------------
操作目的:	得到顺序表指定元素的后继
初始条件:	线性表L已存在
操作结果:	若cur_e是L的数据元素,且不是最后一个,则用nxt_e返
			回它的后继,否则操作失败,nxt_e无定义
函数参数:
		SqList L		线性表L
		ElemType cur_e	数据元素cur_e
		ElemType *nxt_e	后继数据元素
返回值:
		bool				操作是否成功
------------------------------------------------------------*/
bool NextElem(SqList L, ElemType cur_e, ElemType *nxt_e)
{
	int i = LocateElem(L, cur_e, compare);
	if (i!=0 && i != L.length)
	{
		*nxt_e = L.elem[i];
		return true;
	}
	return false;
}

/*------------------------------------------------------------
操作目的:	遍历顺序表
初始条件:	线性表L已存在
操作结果:	依次对L的每个元素调用函数fp
函数参数:
		SqList L		线性表L
		void (*fp)()	访问每个数据元素的函数指针
返回值:
		无
------------------------------------------------------------*/
void ListTraverse(SqList L, void (*fp)(ElemType))
{
	for (int i = 0; i < L.length; i++)
		(*fp)(L.elem[i]);
	printf("\n");
}

/*------------------------------------------------------------
操作目的:	清空顺序表
初始条件:	线性表L已存在
操作结果:	将L置为空表
函数参数:
		SqList *L	线性表L
返回值:
		无
------------------------------------------------------------*/
void ClearList(SqList *L)
{
	L->length = 0;
}

/*------------------------------------------------------------
操作目的:	在顺序表的指定位置插入结点,插入位置i表示在第i个
			元素之前插入
初始条件:	线性表L已存在,1<=i<=ListLength(L) + 1
操作结果:	在L中第i个位置之前插入新的数据元素e,L的长度加1
函数参数:
		SqList *L	线性表L
		int i		插入位置
		ElemType e	待插入的数据元素
返回值:
		bool		操作是否成功
------------------------------------------------------------*/
bool ListInsert(SqList *L, int i, ElemType e)
{
	ElemType* newbase = NULL;
	if (i < 1 || i>L->length + 1)
		return false;
	if (L->length == L->listsize)
	{
		newbase = (ElemType*)realloc(L->elem, (LIST_INIT_SIZE + LISTINCREMENT) * sizeof(ElemType));
		if (!newbase)
			return false;
		else
		{
			L->elem = newbase;
			L->listsize += LISTINCREMENT;
		}
	}
		for (int j = L->length; j >= i; j--)
			L->elem[j] = L->elem[j - 1];
		L->elem[i - 1] = e;
		++L->length;
		return true;
}

/*------------------------------------------------------------
操作目的:	在顺序表的指定位置插入结点,插入位置i表示在第i个
			元素之前插入
初始条件:	线性表L已存在,1<=i<=ListLength(L) + 1
操作结果:	在L中第i个位置之前插入新的数据元素e,L的长度加1
函数参数:
		SqList *L	线性表L
		int i		插入位置
		ElemType e	待插入的数据元素
返回值:
		bool		操作是否成功
------------------------------------------------------------*/
void HeadInsert(SqList* L, ElemType e)							//线性表的头插法
{
	ListInsert(L, 1, e);
}

/*------------------------------------------------------------
操作目的:	在顺序表的指定位置插入结点,插入位置i表示在第i个
			元素之前插入
初始条件:	线性表L已存在,1<=i<=ListLength(L) + 1
操作结果:	在L中第i个位置之前插入新的数据元素e,L的长度加1
函数参数:
		SqList *L	线性表L
		int i		插入位置
		ElemType e	待插入的数据元素
返回值:
		bool		操作是否成功
------------------------------------------------------------*/

void TailInsert(SqList* L, ElemType e)						//线性表的尾插法
{
	ListInsert(L, L->length + 1, e);
}
/*------------------------------------------------------------
操作目的:	删除顺序表的第i个结点
初始条件:	线性表L已存在且非空,1<=i<=ListLength(L)
操作结果:	删除L的第i个数据元素,并用e返回其值,L的长度减1
函数参数:
		SqList *L	线性表L
		int i		删除位置
		ElemType *e	被删除的数据元素值
返回值:
		bool		操作是否成功
------------------------------------------------------------*/
bool ListDelete(SqList* L, int i, ElemType* e)
{
	if (i < 1 || i>L->length)
		return false;
	*e = L->elem[i -1];
	for (int j = i - 1; j < L->length - 1; j++)
	{
		L->elem[j] = L->elem[j + 1];
	}
	--L->length;
	return true;
}

void ListDeleteHead(SqList* L, ElemType* e)							//线性表的头删法
{
	ListDelete(L,1, e);
}
void ListDeleteTail(SqList* L, ElemType* e)							//线性表的尾删法
{
	ListDelete(L, L->length, e);
}


/*------------------------------------------------------------
操作目的:	求两个线性表的并集
初始条件:	两个线性表La 和 Lb 都已存在且非空,1<=i<=ListLength(La)  1<=i<=ListLength(Lb)
操作结果:	打印连接之后的线性表
函数参数:
		SqList* La, SqList* Lb 求并集的两个线性表
返回值:
		void 不需要返回值
------------------------------------------------------------*/
void unionList(SqList* La, SqList Lb)
{
	int La_len = ListLength(*La);
	int Lb_len = ListLength(Lb);
	ElemType e = 0;

	for (int i = 0; i < Lb_len; i++)
	{
		GetElem(Lb, i, &e);		// 取 Lb 中第 i 个数据元素赋给 e   
		if (!LocateElem(*La, e, compare)) //如果e和线性表 La 的所有元素都不想等
			ListInsert(La, La->length, e);		//把 e 插入到La的尾部	
		else
			continue;
	}
}

ElemType.cpp

/***
*ElemType.cpp - ElemType的实现
*	
****/

#include <stdio.h>
#include "ElemType.h"

int compare(ElemType x, ElemType y)
{
	return(x-y);
}

void visit(ElemType e)
{
	printf("%d\t", e);
}

Lab.cpp

#include <stdio.h>
#include "DynaSeqList.h"

int main()
{
	SqList myList;
	if (InitList(&myList))
		printf("初始化成功\n");
	else
		printf("初始化失败\n");

	//头插法
	printf("头插法:\n");
	for (int i = 0; i < 10; i++)
	{
		ListInsert(&myList, i, i * 10);
	}

	ListTraverse(myList, visit);

	ElemType x = 0;
	ElemType data = 0;
	ListDelete(&myList, 2, &x);
	printf("删除的是%d\n", x);
	ListTraverse(myList, visit);

	printf("在线性表头部插入数据元素值为666\n");
	HeadInsert(&myList, 666);
	ListTraverse(myList, visit);

	printf("在线性表尾部插入数据元素值为258\n");
	TailInsert(&myList, 258);
	ListTraverse(myList, visit);


	ListDeleteHead(&myList, &x);
	printf("删除线性表的头部数据元素值为%d\n", x);
	ListTraverse(myList, visit);


	ListDeleteTail(&myList, &x);
	printf("删除线性表的尾部数据元素值为%d\n", x);
	ListTraverse(myList, visit);

	x = 4;
	data = 555;
	if (ListInsert(&myList, x, data))
		printf("成功在第%d的位置插入元素%d\n", x, data);
	else
		printf("在第%d的位置插入失败。\n", x);
	ListTraverse(myList, visit);

	x = 3;
	if (ListDelete(&myList, x, &data))
		printf("成功在第%d的位置删除元素%d\n", x, data);
	else
		printf("在第%d的位置删除失败。\n", x);
	ListTraverse(myList, visit);

	if (ListEmpty(myList))
		printf("线性表为空\n");
	else
		printf("线性表非空\n");

	printf("线性表长度为 %d\n", ListLength(myList));

	x = 5;


	if (GetElem(myList, x, &data))
	{
		printf("第%d位置的数据元素存在\n", x);
	}
	else
	{
		printf("%d位置的数据元素不存在\n", x);
	}

	printf("获得第%d位置的数据元素为%d\n", x, data);

	x = 80;
	printf("线性表中和%d相等的元素为%d\n", x, LocateElem(myList, x, compare));

	x = 5;
	if (GetElem(myList, x, &data))
	{
		printf("位置为%d的元素存在\n", x);
		printf("位置为%d的元素下标为%d\n", x, data);
	}
	else
		printf("位置为%d的元素不存在\n", x);

	x = 70;
	if (PriorElem(myList, x, &data))
		printf("数据元素%d的前驱元素存在,前驱元素数值为%d\n", x, data);
	else
		printf("数据元素%d的前驱元素不存在", x);

	x = 80;
	if (NextElem(myList, x, &data))
		printf("数据元素%d的后继元素存在,后继元素数值为%d\n", x, data);
	else
		printf("数据元素%d的后继元素不存在\n", x);

	printf("清空线性表:\n");
	ClearList(&myList);
	if (!ListLength(myList))
		printf("线性表清空成功\n");
	else
		printf("线性表清空失败\n");

	printf("销毁线性表:\n");
	DestroyList(&myList);
	if (NULL ==myList.elem)
		printf("线性表销毁成功\n");
	else
		printf("线性表销毁失败\n");
	return 0;
}

测试结果

线性表的基本操作测试结果

注意

上面我们所实现的线性表的基本操作数据类型为 int 类型,我们可以把ElemType设置为任何我们所需要的数据类型或者结构体类型,但是所有的操作都不需要搞定从而体现出来数据结构的灵活性,这是非常重要的一点需要读者去深刻体会。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章