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