动态顺序表的实现

上一篇文章静态顺序表的概念及实现
实现了静态顺序表的基本操作,仔细一想,发现静态顺序表好像有缺陷,首先,进程中,需要开辟一大块空间供动态顺序表存储数据用,如果存储的数据不多(结点不多),会浪费很多内存,如果开辟空间比较少,而存储数据较多,就会存在数据存不下的情况,这都不是我们想要的,建立在这样的基础上,动态顺序表的就出现了,先来看一下动态顺序表的结构体:

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;
}

测试结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值