【数据结构】动态顺序表的基本操作

  上一篇实现了静态顺序表的基本操作,由于静态顺序表中结构体的大小无法变化,这会引来诸多不便,例如,结构体中的数组大小太大会造成内存浪费,而开辟的内存过小,又将面临扩容的问题,因此本篇介绍动态顺序表来解决这些问题。

头文件

DynamicSeqList.h

# ifndef __DYNAMICSEQLIST_H__
# define __DYNAMICSEQLIST_H__

# include <stdio.h>
# include <assert.h>
# include <string.h>
# include <stdlib.h>
# include <windows.h>

# define DEFAULT_CAPACITY 3
# define DOUBLE 2

enum OPTION
{
	QUIT, // 退出
	ADD, // 添加
	DETELE, // 删除
	SEARCH, // 查找
	MODIFY, // 修改
	CLEAR, // 清空
	SIZE_DATA, // 大小
	IS_EMPTY, // 判空
	DESTORY, // 销毁
	SORT, // 排序
	SHOW // 显示
};

enum ADD_DATA
{
	EXIT_ADD, // 退出添加
	PUSH_FRONT, // 头插
	PUSH_BACK, // 尾插
	PUSH_INSERT // 任意插
};

enum DELETE_DATA
{
	EXIT_DELETE, // 退出删除
	POP_FRONT, // 头删
	POP_BACK, // 尾删
	POP_ERASE, // 任意删
	REMOVE_FIRST, // 只删除第一个要删除的
	REMOVE_ALL // 删除所有要删除的
};

typedef int DataType;

typedef struct SeqListD
{
	DataType * data; // 数据
	int size; // 大小
	int capacity; // 容量
}SeqListD, *pSeqListD;

void SeqListInit(pSeqListD pSLD); // 初始化
void SeqListPrint(pSeqListD pSLD); // 打印顺序表
void CheckCapacity(pSeqListD pSLD); // 检查是否需要增大容量
void SeqListPushFront(pSeqListD pSLD, DataType data); // 头插
void SeqListPushBack(pSeqListD pSLD, DataType data); // 尾插
void SeqListInsert(pSeqListD pSLD, int pos, DataType data); // 按下标插
void SeqListAdd(pSeqListD pSLD); // 顺序表添加数据
void SeqListPopFront(pSeqListD pSLD); // 头删
void SeqListPopBack(pSeqListD pSLD); // 尾删
void SeqListErase(pSeqListD pSLD, int pos); // 任意删
int SeqListFind(pSeqListD pSLD, DataType data); // 按值查找,返回第一个找到的下标,如果没找到,返回 -1
void SeqListSearch(pSeqListD pSLD); // 查找输入数据,如果找到该数据则返回下标,反之则提示没找到
void SeqListModify(pSeqListD pSLD); // 修改顺序表数据
void SeqListRemove(pSeqListD pSLD, DataType data); // 按值删除,只删除遇到的第一个值
void SeqListRemoveAll(pSeqListD pSLD, DataType data); // 按值删除,删除所有要删除的值
void SeqListDel(pSeqListD pSLD); // 顺序表删除数据
void SeqListEmpty(pSeqListD pSLD); // 判断顺序表是否为空
void SeqListSize(pSeqListD pSLD); // 顺序表的大小
void SeqListSelectSort(pSeqListD pSLD); // 选择排序顺序表中的数据
void SeqListClear(pSeqListD pSLD); // 清空顺序表
void SeqListDestroy(pSeqListD pSLD); // 销毁顺序表

# endif //__DYNAMICSEQLIST_H__

源代码

1.DynamicSeqList.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:DynamicSeqList.c
* 功能:动态顺序表基本操作实现细节
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年5月25日20:23:26
*/

# include "DynamicSeqList.h"

/*
*	函数名称:SeqListInit
*
*	函数功能:顺序表的初始化
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListInit(pSeqListD pSLD)
{
	assert(NULL != pSLD);

	Sleep(1000);

	pSLD->size = 0;
	pSLD->capacity = DEFAULT_CAPACITY;
	pSLD->data = (DataType *)calloc(sizeof(DataType), pSLD->capacity);

	if (NULL != pSLD->data)
	{
		printf("初始化动态顺序表成功!\n");
	}
	else
	{
		perror("初始化动态顺序表失败!\n");
		exit(-1);
	}

	return;
}

/*
*	函数名称:SeqListPrint
*
*	函数功能:打印顺序表
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListPrint(pSeqListD pSLD)
{
	int i = 0;

	assert(NULL != pSLD);

	if (0 >= pSLD->size)
	{
		printf("顺序表为空!\n");
		exit(-1);
	}
	else
	{
		printf("数据为:>\n");

		for (i = 0; i < pSLD->size; i++)
		{
			printf("%d\t", pSLD->data[i]);
		}

		printf("\n");
	}

	return;
}

/*
*	函数名称:CheckCapacity
*
*	函数功能:检查是否需要增大容量
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void CheckCapacity(pSeqListD pSLD)
{
	assert(NULL != pSLD);

	if (pSLD->size == pSLD->capacity)
	{
		DataType * pNewData = (DataType *)realloc(pSLD->data, sizeof(DataType) * ((pSLD->capacity)*DOUBLE));

		if (NULL != pNewData)
		{
			pSLD->data = pNewData;
			//pNewData的地址赋给了pSLD->data,此时不需要pNewData了
			pNewData = NULL;
		}
		else
		{
			perror("扩大容量失败!\n");
			exit(-1);
		}

		pSLD->capacity *= DOUBLE;
		printf("扩大容量成功!\n");
	}
	else
	{
		;
	}

	return;
}

/*
*	函数名称:AddMenu
*
*	函数功能:添加数据菜单显示
*
*	入口参数:void
*
*	出口参数:select
*
*	返回类型:int
*/

int AddMenu(void)
{
	int select = 0;

	printf("************************************\n");
	printf("*******        添加数据      *******\n");
	printf("*******  1. 头插    2. 尾插  *******\n");
	printf("*******  3. 任意插  0. 退出  *******\n");;
	printf("************************************\n");
	printf("select>");

	assert(1 == scanf("%d", &select));

	return select;
}

/*
*	函数名称:SeqListPushFront
*
*	函数功能:顺序表的头插
*
*	入口参数:pSLD, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListPushFront(pSeqListD pSLD, DataType data)
{
	int i = 0;

	assert(NULL != pSLD);
		
	CheckCapacity(pSLD);

	for (i = pSLD->size - 1; i >= 0; i--)
	{
		pSLD->data[i + 1] = pSLD->data[i];
	}

	pSLD->data[0] = data;
	pSLD->size++;

	return;
}

/*
*	函数名称:SeqListPushBack
*
*	函数功能:顺序表的尾插
*
*	入口参数:pSLD, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListPushBack(pSeqListD pSLD, DataType data)
{
	assert(NULL != pSLD);
		
	CheckCapacity(pSLD);

	pSLD->data[pSLD->size] = data;
	pSLD->size++;

	return;
}

/*
*	函数名称:SeqListInsert
*
*	函数功能:按下标插入,pos 的范围是 [0, size] 
*
*	入口参数:pSLD, pos, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListInsert(pSeqListD pSLD, int pos, DataType data)
{
	int i = 0;

	assert(NULL != pSLD);
	assert((pos >= 0) && (pos <= pSLD->size));

	CheckCapacity(pSLD);
	
	for (i = pSLD->size-1; i >= pos; i--)
	{
		pSLD->data[i + 1] = pSLD->data[i];
	}

	pSLD->data[pos] = data;
	pSLD->size++;
	
	return;
}

/*
*	函数名称:SeqListAdd
*
*	函数功能:顺序表的插入
*
*	入口参数:pSLD, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListAdd(pSeqListD pSLD)
{
	DataType data = 0;
	int select = AddMenu();

	assert(NULL != pSLD);

	switch (select)
	{
		case EXIT_ADD:
		{
			printf("退出添加!\n");
			break;
		}
		case PUSH_FRONT:
		{
			printf("请输入要添加的数据:>");
			assert(1 == scanf("%d", &data));

			SeqListPushFront(pSLD, data);
			printf("头插成功!\n");

			break;
		}
		case PUSH_BACK:
		{
			printf("请输入要添加的数据:>");
			assert(1 == scanf("%d", &data));

			SeqListPushBack(pSLD, data);
			printf("尾插成功!\n");

			break;
		}
		case PUSH_INSERT:
		{
			int pos = 0;
			
			printf("请输入要添加的数据:>");
			assert(1 == scanf("%d", &data));

			printf("请输入下标:>");
			assert(1 == scanf("%d", &pos));
			SeqListInsert(pSLD, pos, data);
			printf("任意插成功!\n");

			break;
		}
		default:
		{
			printf("输入有误!\n");
			break;
		}
	}

	return;
}

/*
*	函数名称:DelMenu
*
*	函数功能:删除数据菜单显示
*
*	入口参数:void
*
*	出口参数:select
*
*	返回类型:int
*/

int DelMenu(void)
{
	int select = 0;

	printf("************************************************************************\n");
	printf("*******                   删除数据                               *******\n");
	printf("*******    1. 头删                  2. 尾删                      *******\n");
	printf("*******    3. 任意删                4. 只删除要删数据中的第一个  *******\n");;
	printf("*********  5. 删除所有要删除的数据  0.退出                       *******\n");
	printf("************************************************************************\n");
	printf("select>");

	assert(1 == scanf("%d", &select));

	return select;
}

/*
*	函数名称:SeqListPopFront
*
*	函数功能:顺序表的头删
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListPopFront(pSeqListD pSLD)
{
	int i = 0;

	assert(NULL != pSLD);
		
	if (0 >= pSLD->size)
	{
		printf("顺序表为空!\n");
		exit(-1);
	}
	else
	{
		for (i = 0; i < pSLD->size - 1; i++)
		{
			pSLD->data[i] = pSLD->data[i + 1];
		}

		pSLD->size--;
	}

	return;
}

/*
*	函数名称:SeqListPopBack
*
*	函数功能:顺序表的尾删
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListPopBack(pSeqListD pSLD)
{
	assert(NULL != pSLD);
		
	if (0 >= pSLD->size)
	{
		printf("顺序表为空!\n");
		exit(-1);
	}
	else
	{
		pSLD->size--;
	}

	return;
}

/*
*	函数名称:SeqListErase
*
*	函数功能:按下标删除,pos 的范围是 [0, size)  
*
*	入口参数:pSLD, pos
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListErase(pSeqListD pSLD, int pos)
{
	int i = 0;

	assert(NULL != pSLD);
	assert((pos >= 0) && (pos < pSLD->size));
	
	if (0 >= pSLD->size)
	{
		printf("顺序表为空!\n");
		exit(-1);
	}
	else
	{
		for (i = pos; i < pSLD->size - 1; i++)
		{
			pSLD->data[i] = pSLD->data[i + 1];
		}

		pSLD->size--;
	}
	
	return;
}

/*
*	函数名称:SeqListFind
*
*	函数功能:按值查找,返回第一个找到的下标,如果没找到,返回 -1 
*
*	入口参数:pSLD, data
*
*	出口参数:pos or -1
*
*	返回类型:int
*/

int SeqListFind(pSeqListD pSLD, DataType data)
{
	int pos = 0;

	assert(NULL != pSLD);

	for (pos = 0; pos < pSLD->size; pos++)
	{
		if (data == pSLD->data[pos])
		{
			return pos;
		}
		else
		{
			;
		}
	}

	return -1;
}

/*
*	函数名称:SeqListSearch
*
*	函数功能:查找输入数据,如果找到该数据则返回下标,反之则提示没找到 
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListSearch(pSeqListD pSLD)
{
	DataType data = 0;
	int pos = 0;

	assert(NULL != pSLD);

	printf("请输入要查找的数据:>");
	assert(1 == scanf("%d", &data));
	pos = SeqListFind(pSLD, data);

	if (-1 != pos)
	{
		printf("找到了%d,它的下标是%d\n", data, pos);
	}
	else
	{
		printf("没找到%d\n", data);
	}

	return;
}

/*
*	函数名称:SeqListModify
*
*	函数功能:修改顺序表数据 
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListModify(pSeqListD pSLD)
{
	int pos = 0;
	DataType data = 0;

	assert(NULL != pSLD);

	printf("请输入修改数据的下标:>");
	assert(1 == scanf("%d", &pos));

	if (pos < 0 || pos > pSLD->size - 1)
	{
		printf("输入下标有误!请重新输入下标:>");
		assert(1 == scanf("%d", &pos));
	}
	else
	{
		;
	}

	printf("请输入修改后的数据:>");
	assert(1 == scanf("%d", &data));

	pSLD->data[pos] = data;

	printf("修改成功!\n");

	return;
}

/*
*	函数名称:SeqListRemove
*
*	函数功能:按值删除,只删除遇到的第一个值
*
*	入口参数:pSLD, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListRemove(pSeqListD pSLD, DataType data)
{
	int pos = 0;

	assert(NULL != pSLD);

	if (0 >= pSLD->size)
	{
		printf("顺序表为空!\n");
		exit(-1);
	}
	else
	{
		pos = SeqListFind(pSLD, data);

		if (-1 != pos)
		{
			SeqListErase(pSLD, pos);
		}
		else
		{
			printf("要删除的数据不存在!\n");;
		}
	}

	return;
}

/*
*	函数名称:SeqListRemoveAll
*
*	函数功能:按值删除,删除所有要删除的值
*
*	入口参数:pSLD, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListRemoveAll(pSeqListD pSLD, DataType data)
{
	assert(NULL != pSLD);

	if (0 >= pSLD->size)
	{
		printf("顺序表为空!\n");
		exit(-1);
	}
	else
	{
		int count = 0;
		int dest = 0;
		int i = 0;

		for (i = 0; i < pSLD->size; i++)
		{
			if (data == pSLD->data[i])
			{
				count++;
			}
			else
			{
				pSLD->data[dest] = pSLD->data[i];
				dest++;
			}
		}

		pSLD->size -= count;
	}

	return;
}

/*
*	函数名称:SeqListDel
*
*	函数功能:顺序表的删除
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListDel(pSeqListD pSLD)
{
	DataType data = 0;
	int select = DelMenu();

	assert(NULL != pSLD);

	switch (select)
	{
		case EXIT_DELETE:
		{
			printf("退出删除!\n");
			break;
		}
		case POP_FRONT:
		{
			SeqListPopFront(pSLD);
			printf("头删成功!\n");

			break;
		}
		case POP_BACK:
		{
			SeqListPopBack(pSLD);
			printf("尾删成功!\n");

			break;
		}
		case POP_ERASE:
		{
			int pos = 0;

			printf("请输入要删除数据的下标:>");
			assert(1 == scanf("%d", &pos));

			SeqListErase(pSLD, pos);
			printf("任意删成功!\n");

			break;
		}
		case REMOVE_FIRST:
		{
			printf("请输入要删除的数据:>");
			assert(1 == scanf("%d", &data));

			SeqListRemove(pSLD, data);
			printf("删除第一个要删除的数据成功!\n");

			break;
		}
		case REMOVE_ALL:
		{
			printf("请输入要删除的数据:>");
			assert(1 == scanf("%d", &data));

			SeqListRemoveAll(pSLD, data);
			printf("要删除的数据删除成功!\n");

			break;
		}
		default:
		{
			printf("输入有误!\n");
			break;
		}
	}

	return;
}

/*
*	函数名称:SeqListEmpty
*
*	函数功能:判断顺序表是否为空,1表示空,0表示非空
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListEmpty(pSeqListD pSLD)
{
	assert(NULL != pSLD);

	if (0 == pSLD->size)
	{
		printf("顺序表为空!\n");
	}
	else
	{
		printf("顺序表不为空!\n");
	}
	return;
}

/*
*	函数名称:SeqListSize
*
*	函数功能:顺序表的大小
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListSize(pSeqListD pSLD)
{
	assert(NULL != pSLD);

	if (0 >= pSLD->size)
	{
		printf("顺序表为空!\n");
	}
	else
	{
		printf("顺序表大小为: %d\n", pSLD->size);
	}
	return;
}

/*
*	函数名称:Swap
*
*	函数功能:交换顺序
*
*	入口参数:p1, p2
*
*	出口参数:void
*
*	返回类型:void
*/

void Swap(DataType * p1, DataType * p2)
{
	DataType tmp = 0;

	assert((NULL != p1) && (NULL != p2));

	tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;

	return;
}

/*
*	函数名称:SeqListSelectSort
*
*	函数功能:选择排序顺序表中的数据
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListSelectSort(pSeqListD pSLD)
{
	int i = 0;
	int j = 0;
	int minPos = 0;
	int maxPos = 0;

	assert(NULL != pSLD);

	for (i = 0; i < pSLD->size / 2; i++) 
	{
		minPos = maxPos = i;

		for (j = i; j < pSLD->size - i; j++) 
		{
			if (pSLD->data[j] < pSLD->data[minPos]) 
			{
				minPos = j;
			}
			else
			{
				;
			}

			if (pSLD->data[j] > pSLD->data[maxPos]) 
			{
				maxPos = j;
			}
			else
			{
				;
			}
		}

		Swap(pSLD->data + i, pSLD->data + minPos);

		if (i == maxPos) 
		{
			maxPos = minPos;
		}
		else
		{
			;
		}

		Swap(pSLD->data + pSLD->size - i - 1, pSLD->data + maxPos);
	}

	return;
}

/*
*	函数名称:SeqListClear
*
*	函数功能:清空顺序表
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/	

void SeqListClear(pSeqListD pSLD)
{
	assert(NULL != pSLD);

	pSLD->size = 0;
	pSLD->capacity = 0;
	memset(pSLD->data, 0, sizeof(pSLD->data));

	printf("清空动态顺序表成功!\n");

	return;
}

/*
*	函数名称:SeqListDestroy
*
*	函数功能:销毁顺序表
*
*	入口参数:pSLD
*
*	出口参数:void
*
*	返回类型:void
*/

void SeqListDestroy(pSeqListD pSLD)
{
	assert(NULL != pSLD);

	Sleep(1000);

	free(pSLD->data);
	pSLD->data = NULL;
	pSLD->size = 0;
	pSLD->capacity = 0;

	printf("销毁动态顺序表成功!\n");

	return;
}

2.test.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:test.c
* 功能:测试动态顺序表基本功能
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年5月25日20:25:42
*/

# include "DynamicSeqList.h"

/*
*	函数名称:MainMenu
*
*	函数功能:动态顺序表主菜单显示
*
*	入口参数:void
*
*	出口参数:choose
*
*	返回类型:int
*/

int MainMenu(void)
{
	int choose = 0;

	printf("**************************************\n");
	printf("*******    欢迎操作动态顺序表   ********\n");
	printf("*******  1. 添加      2. 删除  ********\n");
	printf("*******  3. 查找      4. 修改  ********\n");
	printf("*******  5. 清空      6. 数量  ********\n");
	printf("*******  7. 判空      8. 销毁  ********\n");
	printf("*******  9. 排序     10. 显示  ********\n");
	printf("*******        0. 退出         ********\n");
	printf("***************************************\n");
	printf("choose>");

	assert(1 == scanf("%d", &choose));

	return choose;
}

/*
*	函数名称:main
*
*	函数功能:主程序
*
*	入口参数:void
*
*	出口参数:0
*
*	返回类型:int
*/

int main(void)
{
	int choose = 0;
	SeqListD dsql;
	//初始化动态顺序表
	SeqListInit(&dsql);

	do
	{
		choose = MainMenu();

        switch(choose)
		{
			case QUIT:
				printf("退出动态顺序表!\n");
				break;
			case ADD:
				SeqListAdd(&dsql);
				SeqListAdd(&dsql);
				SeqListAdd(&dsql);
				break;
			case DETELE:
				SeqListDel(&dsql);
				break;
			case SEARCH:
				SeqListSearch(&dsql);
				break;
			case MODIFY:
				SeqListModify(&dsql);
				break;
			case CLEAR:
				SeqListClear(&dsql);
				break;
			case SIZE_DATA:
				SeqListSize(&dsql);
				break;
			case IS_EMPTY:
				SeqListEmpty(&dsql);
				break;
			case DESTORY:
				SeqListDestroy(&dsql);
				break;
			case SORT:
				SeqListSelectSort(&dsql);
				break;
			case SHOW:
				SeqListPrint(&dsql);
				break;
			default:
				printf("输入有误,请重新输入!\n");
				break;
		}
	}while(choose);

	return 0;
}

输出结果





猜你喜欢

转载自blog.csdn.net/sustzc/article/details/80509080