上一篇文章静态顺序表的基本操作
实现了静态顺序表的基本操作,仔细一想,发现静态顺序表好像有缺陷,首先,进程中,需要开辟一大块空间供动态顺序表存储数据用,如果存储的数据不多(结点不多),会浪费很多内存,如果开辟空间比较少,而存储数据较多,就会存在数据存不下的情况,这都不是我们想要的,建立在这样的基础上,动态顺序表的就出现了,先来看一下动态顺序表的结构体:
typedef int DataType;
typedef struct SeqList
{
DataType* _a; //数据块指针
int _size; // 有效数据个数
int _capacity; // 容量
}SeqListD;
typedef SeqListD* PSeqListD;
这里的数据块指针是数据在内存中存储的首地址,就像数组的地址一样。
SeqListD.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>
#define INIT_SIZE 10
#define INCREMENT 5
typedef int DataType;
typedef struct SeqList
{
DataType* _a; //数据块指针
int _size; // 有效数据个数
int _capacity; // 容量
}SeqListD;
typedef SeqListD* PSeqListD;
//动态顺序表初始化
void SeqListDInit(PSeqListD ps);
//动态顺序表尾插
void SeqListDPushBack(PSeqListD ps, DataType data);
//动态顺序表尾删
void SeqListDPopBack(PSeqListD ps);
//动态顺序表头插
void SeqListDPushFront(PSeqListD ps, DataType data);
//动态顺序表头删
void SeqListDPopFront(PSeqListD ps);
//指定位置插入
void SeqListDInsert(PSeqListD ps, int pos, DataType data);
//指定位置删除
void SeqListDErase(PSeqListD ps, int pos);
//在动态顺序表中查找元素data,找到返回下标,找不到返回-1
int Find(PSeqListD ps, DataType data);
//删除动态顺序表中第一个data元素
void Remove(PSeqListD ps, DataType data);
//删除顺序表中所有data元素
void RemoveAll(PSeqListD ps, DataType data);
//顺序表遍历
void PrintSeqListD(PSeqListD ps);
// 获取元素个数
int SeqListDSize(PSeqListD ps);
// 获取顺序表的容量
int SeqListDCapacity(PSeqListD ps);
//判空
int SeqListDEmpty(PSeqListD ps);
// 将顺序表中的元素清空 注意:不改变顺序表空间的大小
void SeqListDClear(PSeqListD ps);
void SeqListDDestroy(PSeqListD ps);
//检查当前线性表的容量,不够的话申请内存
void CheckCapacity(PSeqListD ps);
//冒泡排序,升序和降序两种版本,用了函数指针
void BubbleSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2));
//选择排序,升序和降序两种版本,用了函数指针
void SelectSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2));
//升序比较
int CmpInAscendingOrder(const void *elem1, const void *elem2);
//降序比较
int CmpInDescendingOrder(const void *elem1, const void *elem2);
//二分查找
int BinarySearch(PSeqListD ps, DataType data);
SeqListD.c
#include "SeqListD.h"
//检查当前线性表的容量,不够的话申请内存
void CheckCapacity(PSeqListD ps)
{
//参数检验
assert(ps);
if (ps->_size >= ps->_capacity)
{
DataType *p = (DataType *)realloc(ps->_a, (ps->_capacity + INCREMENT) * sizeof(DataType));
if (NULL == p)
{
printf("增容失败!\n");
return;
}
else
{
ps->_a = p;
ps->_capacity += INCREMENT;
}
}
}
//动态顺序表的初始化
void SeqListDInit(PSeqListD ps)
{
//参数检验
assert(ps);
ps->_a = (DataType *)malloc(sizeof(DataType) * INIT_SIZE);
if (NULL == ps->_a)
{
printf("内存申请失败!!!\n");
return;
}
else
{
ps->_size = 0;
ps->_capacity = INIT_SIZE;
}
}
//尾插
void SeqListDPushBack(PSeqListD ps, DataType data)
{
//参数检验
assert(ps);
CheckCapacity(ps);
ps->_a[ps->_size] = data;
ps->_size++;
}
//尾删
void SeqListDPopBack(PSeqListD ps)
{
//参数检验
assert(ps);
if (0 == ps->_size)
{
printf("顺序表已空!\n");
return;
}
else
{
ps->_size--;
}
}
//头插
void SeqListDPushFront(PSeqListD ps, DataType data)
{
int i = 0;
//参数检验
assert(ps);
CheckCapacity(ps);
//先把原来所有元素后移
i = ps->_size;
while (i != 0)
{
ps->_a[i] = ps->_a[i-1];
i--;
}
//再把元素插到第一个位置
ps->_a[0] = data;
//插入之后,让size++
ps->_size++;
}
//动态顺序表头删
void SeqListDPopFront(PSeqListD ps)
{
int i = 0;
// 参数检验
assert(ps);
while (i < ps->_size)
{
ps->_a[i] = ps->_a[i + 1];
i++;
}
//移除之后让size--
ps->_size--;
}
//顺序表指定位置插入
void SeqListDInsert(PSeqListD ps, int pos, DataType data)
{
int i = 0;
//参数检验
assert(ps);
if ((pos < 1) || (pos > ps->_size))
{
printf("pos位置不合法!\n");
return;
}
else
{
int turepos = pos - 1;
i = ps->_size;
while (i != turepos)
{
ps->_a[i] = ps->_a[i-1];
i--;
}
ps->_a[turepos] = data;
ps->_size++;
}
}
//指定位置删除
void SeqListDErase(PSeqListD ps, int pos)
{
int i = 0;
//参数检验
assert(pos);
if ((pos < 1) || (pos > ps->_size))
{
printf("pos位置不合法!\n");
return;
}
else
{
i = pos - 1;
while (i < ps->_size - 1)
{
ps->_a[i] = ps->_a[i+1];
i++;
}
ps->_size--;
}
}
//在动态顺序表中查找元素data,找到返回下标,找不到返回-1
int Find(PSeqListD ps, DataType data)
{
int i = 0;
//参数检验
assert(ps);
while (i < ps->_size)
{
if (data == ps->_a[i])
{
return i;
}
i++;
}
return -1;
}
//删除动态顺序表中第一个data元素
void Remove(PSeqListD ps, DataType data)
{
int ret_Find = 0;
//参数检验
assert(ps);
ret_Find = Find(ps, data);
if (-1 == ret_Find)
{
printf("顺序表中无 %d 元素\n", data);
return;
}
else
{
//方法一:利用SeqListDErase(ps, ret_Find+1)函数
//SeqListDErase(ps, ret_Find+1);
//方法二
int i = ret_Find;
while (i < ps->_size-1)
{
ps->_a[i] = ps->_a[i + 1];
i++;
}
ps->_size--;
}
}
//删除顺序表中所有data元素
void RemoveAll(PSeqListD ps, DataType data)
{
int i = 0;//i当作循环变量,遍历顺序表
int count = 0;//统计在顺序表中删了多少个值data的元素个数
int index = 0;//辅助删除的变量
//参数检验
assert(ps);
while (i < ps->_size)
{
if (data == ps->_a[i])
{
//遇到值为data的元素,跳过,并让计数器+1
i++;
count++;
continue;
}
ps->_a[index] = ps->_a[i];//依次赋值
i++;
index++;
}
//最后让用来统计顺序表中元素个数的size-count,得到现在顺序表中所有元素个数
ps->_size -= count;
printf("动态顺序表中所有值为%d的元素已删除\n", data);
}
//顺序表遍历
void PrintSeqListD(PSeqListD ps)
{
int i = 0;
//参数检验
assert(ps);
printf("顺序表中所有元素:\n");
while (i < ps->_size)
{
printf("%d ", ps->_a[i]);
i++;
}
printf("\n");
}
// 获取元素个数
int SeqListDSize(PSeqListD ps)
{
assert(ps);
return ps->_size;
}
// 获取顺序表的容量
int SeqListDCapacity(PSeqListD ps)
{
assert(ps);
return ps->_capacity;
}
// 判空
int SeqListDEmpty(PSeqListD ps)
{
assert(ps);
return ps->_size;
}
// 将顺序表中的元素清空 注意:不改变顺序表空间的大小
void SeqListDClear(PSeqListD ps)
{
assert(ps);
ps->_size = 0;
}
//动态顺序表销毁
void SeqListDDestroy(PSeqListD ps)
{
assert(ps);
free(ps->_a);
ps->_a = NULL;
ps->_capacity = 0;
ps->_size = 0;
}
//升序比较
int CmpInAscendingOrder(const void *elem1, const void *elem2)
{
return *(int *)elem1 - *(int *)elem2;
}
//降序比较
int CmpInDescendingOrder(const void *elem1, const void *elem2)
{
return *(int *)elem2 - *(int *)elem1;
}
//交换
void swap(DataType *a, DataType *b)
{
DataType temp = *a;
*a = *b;
*b = temp;
}
//冒泡排序,升序和降序两种版本,用了函数指针
void BubbleSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2))
{
int i = 0;
int j = 0;
int flag = 0; // 设置一个标签,如果一次循环中flag值始终,没改变,证明数组内元素已经有序
//参数检验
assert(ps);
for (i = 0; i < ps->_size - 1; i++)
{
flag = 0; // 把flag重置为0,方便下一次循环里有没有交换元素
for (j = 0; j < ps->_size - 1 - i; j++)
{
if (cmp(&ps->_a[j], &ps->_a[j + 1]) > 0)
{
swap(&ps->_a[j], &ps->_a[j + 1]);
flag = 1;
}
}
if (flag == 0)
{
break;
}
}
}
//选择排序,升序和降序两种版本,用了函数指针
void SelectSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2))
{
int i = 0;
int j = 0;
int pos = 0; // 用来记录最值位置
//参数检验
assert(ps);
for (i = 0; i < ps->_size - 1; i++)
{
pos = i;
for (j = i + 1; j < ps->_size; j++)
{
if (cmp(&ps->_a[j], &ps->_a[pos]) < 0)
{
pos = j;
}
}
if (i != pos)
{
swap(&ps->_a[i], &ps->_a[pos]);
}
}
}
//二分查找
int BinarySearch(PSeqListD ps, DataType data)
{
int left = 0;
int right = 0;
int mid = 0;
// 参数检验
assert(ps);
right = ps->_size - 1;
while (left <= right)
{
mid = left + (right - left) / 2;
if (data < ps->_a[mid])
{
right = mid - 1;
}
else if (data > ps->_a[mid])
{
left = mid + 1;
}
else
{
return mid;
}
}
return -1;
}
测试函数
1.TestSeqListDInit_PushBack_PopBack
测试动态顺序表的初始化、尾插和尾删操作
#include "SeqListD.h"
void TestSeqListDInit_PushBack_PopBack()
{
SeqListD s;//定义顺序表
SeqListDInit(&s);//初始化
SeqListDPushBack(&s, 1);//尾插元素
SeqListDPushBack(&s, 2);
SeqListDPushBack(&s, 3);
SeqListDPushBack(&s, 4);
PrintSeqListD(&s);//顺序表遍历
SeqListDPopBack(&s);//尾删一个元素
PrintSeqListD(&s);//顺序表遍历
}
//主函数
int main()
{
TestSeqListDInit_PushBack_PopBack();
system("pause");
return 0;
}
测试结果:
2.TestSeqListDPushFront_PopFront
测试动态顺序表的头插和头删操作
#include "SeqListD.h"
void TestSeqListDPushFront_PopFront()
{
SeqListD s;//定义顺序表
SeqListDInit(&s);//初始化
SeqListDPushFront(&s, 4);//头插元素
SeqListDPushFront(&s, 3);
SeqListDPushFront(&s, 2);
SeqListDPushFront(&s, 1);
PrintSeqListD(&s);//顺序表遍历
SeqListDPopFront(&s);//头删一个元素
PrintSeqListD(&s);//顺序表遍历
}
//主函数
int main()
{
TestSeqListDPushFront_PopFront();
system("pause");
return 0;
}
测试结果:
3.TestSeqListDInsert_Erase
测试动态顺序表指定位置插入和删除
#include "SeqListD.h"
void TestSeqListDInsert_Erase()
{
SeqListD s;//定义顺序表
SeqListDInit(&s);//初始化
SeqListDPushBack(&s, 1);//尾插元素
SeqListDPushBack(&s, 2);
SeqListDPushBack(&s, 4);
SeqListDPushBack(&s, 5);
PrintSeqListD(&s);//顺序表遍历
SeqListDInsert(&s, 3, 3);//指定位置插入
PrintSeqListD(&s);//顺序表遍历
SeqListDErase(&s, 5);//指定位置删除
PrintSeqListD(&s);//顺序表遍历
}
//主函数
int main()
{
TestSeqListDInsert_Erase();
system("pause");
return 0;
}
测试结果:
4.TestSeqListDRemove_RemoveAll
测试删除顺序表中某元素的第一次出现和删除顺序表中的所有出现
#include "SeqListD.h"
void TestSeqListDRemove_RemoveAll()
{
SeqListD s;// 定义顺序表
SeqListDInit(&s);// 初始化
SeqListDPushBack(&s, 1);// 尾插元素
SeqListDPushBack(&s, 2);
SeqListDPushBack(&s, 3);
SeqListDPushBack(&s, 2);
SeqListDPushBack(&s, 4);
SeqListDPushBack(&s, 2);
SeqListDPushBack(&s, 5);
PrintSeqListD(&s);// 顺序表遍历
Remove(&s, 2);// 删除顺序表中的第一个值为2的元素
PrintSeqListD(&s);// 顺序表遍历
RemoveAll(&s, 2);// 删除顺序表中所有值为2的元素
PrintSeqListD(&s);// 顺序表遍历
}
//主函数
int main()
{
TestSeqListDRemove_RemoveAll();
system("pause");
return 0;
}
测试结果:
5.TestSeqListDSize_Capacity_Empty_Clear_Destorday
测试获取顺序表个数、顺序表容量、判断顺序表是否为空、顺序表清空、摧毁顺序表
#include "SeqListD.h"
void TestSeqListDSize_Capacity_Empty_Clear_Destorday()
{
SeqListD s;//定义顺序表
int ret_Size = 0;
int ret_Capacity = 0;
int ret_Empty = 0;
SeqListDInit(&s);//初始化
SeqListDPushBack(&s, 1);//尾插元素
SeqListDPushBack(&s, 2);
SeqListDPushBack(&s, 3);
SeqListDPushBack(&s, 4);
PrintSeqListD(&s);//遍历顺序表
ret_Size = SeqListDSize(&s);//获取顺序表中元素个数
printf("Size = %d\n", ret_Size);
ret_Capacity = SeqListDCapacity(&s);//获取顺序表的容量
printf("Catacity = %d\n", ret_Capacity);
ret_Empty = SeqListDEmpty(&s);//判空
if (0 == ret_Empty)
{
printf("顺序表为空\n");
}
else
{
printf("顺序表不为空\n");
}
SeqListDClear(&s);//清空顺序表
SeqListDDestroy(&s);//摧毁顺序表
}
//主函数
int main()
{
TestSeqListDSize_Capacity_Empty_Clear_Destorday();
system("pause");
return 0;
}
测试结果:
6.TestSeqListDBubbleSort_SelectSort
测试冒泡排序和选择排序
#include "SeqListD.h"
void TestSeqListDBubbleSort_SelectSort()
{
SeqListD s;
int ret_BubbleFind = 0;
int ret_SelectFind = 0;
SeqListDInit(&s);
SeqListDPushBack(&s, 1);
SeqListDPushBack(&s, 3);
SeqListDPushBack(&s, 2);
SeqListDPushBack(&s, 7);
SeqListDPushBack(&s, 4);
SeqListDPushBack(&s, 5);
SeqListDPushBack(&s, 8);
SeqListDPushBack(&s, 6);
PrintSeqListD(&s);
BubbleSort(&s, CmpInAscendingOrder);
PrintSeqListD(&s);
ret_BubbleFind = BinarySearch(&s, 2);
if (-1 == ret_BubbleFind)
{
printf("顺序表中无此元素\n");
}
else
{
printf("找到了,下标为%d\n", ret_BubbleFind);
}
BubbleSort(&s, CmpInDescendingOrder);
PrintSeqListD(&s);
SelectSort(&s, CmpInAscendingOrder);
PrintSeqListD(&s);
ret_SelectFind = BinarySearch(&s, 2);
if (-1 == ret_SelectFind)
{
printf("顺序表中无此元素\n");
}
else
{
printf("找到了,下标为%d\n", ret_SelectFind);
}
SelectSort(&s, CmpInDescendingOrder);
PrintSeqListD(&s);
SeqListDDestroy(&s);
}
int main()
{
TestSeqListDBubbleSort_SelectSort();
system("pause");
return 0;
}
测试结果: