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設置爲任何我們所需要的數據類型或者結構體類型,但是所有的操作都不需要搞定從而體現出來數據結構的靈活性,這是非常重要的一點需要讀者去深刻體會。

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