通用型动态数组的总结

基本数据结构之-通用型动态数组

动态数组的应用主要是对于长度未知的数组,先开辟一段空间来存储数据,当空间不够时,在开辟两倍的空间来存储数据

和普通数组的区别就是,我们可以不用关心数组的长度的问题,唯一需要关注的就是数据的类型是自定义数据类型还是基本数据类型,但是不论是基本数据类型还是自定义的数据类型,都需要自定义两个函数,这两个函数时遍历(打印)函数和比较函数,因为,在传递的是地址,没法再里面判断是什么类型,只能交给使用者去定义它的想关的函数,

先说基本的结构:

为了适应更多的数据类型,我们存储的只是数据的的地址(void *),其实我们更关注的是数据存储的那块首地址,因此我们使用void ** 来存储数据存储区域的首地址;

为了更好的操作数组,我们需要维护两个变量,一个是容量,一个是长度,当数组的长度和容量相同时,我们就需要重新开辟一段空间来存储现在的数据和即将放入数组的数据。

直接上代码:

typedef struct _DYNAMICARRAY

{

// 数据存储

void **Array;

// 数组的容量

int Capacity;

// 数组现有数据的长度

int ArrayLen;

}DynamicArray;

自定义的数据类型,我们就必须定义自己的初始化函数

int Init_DynamicArray(void **DArray)

{

if (DArray == NULL)

{

exit(-1);

}

DynamicArray *dynamicarray = (DynamicArray *)malloc(sizeof(DynamicArray));

dynamicarray->Array = (void **)malloc(sizeof(void *)*MAXCAPACITY);

if (dynamicarray->Array == NULL)

{

exit(-2);

}

for (int i = 0; i < MAXCAPACITY; ++i)

{

// 将开辟void * 指针指向NULL

//dynamicarray->Array[i] = NULL;

*((dynamicarray->Array) + i) = NULL;

}

// 将数组的变化写入想关数据

dynamicarray->ArrayLen = 0;

dynamicarray->Capacity = MAXCAPACITY;

*DArray = dynamicarray;

return 0;

}

数组有顺序插入的特性,当然你也可以在数组内随机插入,但是插入一般是不允许的,因为你插入的数据对数组来说可能无法访问,因此虽然提供了随机插入函数,但是,并不会对数据的长度和容量带来改变,因为我不确定,你插入数据的意图,如果你插入的数据的位置刚好在数组可以允许范围类,那么你就修改了当前的值,如果你插入的不在允许的范围内,那么对数组的原有数据是没有影响的e

// 在数组末尾插入数据

int pushBack_DynamicArray(void *DArray, void *Data)

{

if (DArray == NULL)

{

return -1;

}

if (Data == NULL)

{

return -2;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

if (dynamicarray->ArrayLen == dynamicarray->Capacity)

{

void ** tempCapaticy = (void **)malloc(sizeof(void *)*dynamicarray->Capacity * 2);

if (tempCapaticy == NULL)

{

return -3;

}

memcpy(tempCapaticy, dynamicarray->Array, sizeof(void *)*dynamicarray->Capacity);

free(dynamicarray->Array);

dynamicarray->Array = tempCapaticy;

for (int i = dynamicarray->Capacity; i < dynamicarray->Capacity * 2; ++i)

{

dynamicarray->Array[i] = NULL;

}

dynamicarray->Capacity *= 2;

}

dynamicarray->Array[dynamicarray->ArrayLen] = Data;

++dynamicarray->ArrayLen;

return 0;

}

// 指定位置插入函数,如果在数组允许的范围内,则起到修改该位置的元素的作用,如果在不允许的范围类,可能导致程崩溃,当然你也可修改源码,来使插入合法

// 指定位置插入

void InsertByPos(void *DArray, int Pos, void *Val)

{

if (DArray == NULL)

{

return;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

dynamicarray->Array[Pos] = Val;

}

删除某个位置的数据,这个可能和原生数组有些差别,因为原生数据没有删除单个数据的功能,我做了如下的处理,当删除某个数据时,我把后面的数据向前移动一个位置,覆盖原来的数据

//  指定位置删除

int eraseByPos_DynamicArray(void *DArray, int Pos)

{

if (DArray == NULL)

{

return -1;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

if (Pos < 0 || Pos >= dynamicarray->ArrayLen)

{

return -2;

}

for (int i = Pos; i < dynamicarray->ArrayLen - 1; ++i)

{

dynamicarray->Array[i] = dynamicarray->Array[i + 1];

}

dynamicarray->Array[dynamicarray->ArrayLen - 1] = NULL;

--dynamicarray->ArrayLen;

return 0;

}

// 头删 (这个基本数据类型的数组也是没有的,但是作为自己定义的数据类型,为了操作的方便,自己加上的)

int eraseFront_DynamicArray(void *DArray)

{

int ret = eraseByPos_DynamicArray(DArray, 0);

return ret;

}

// 尾删(同头删)

int eraseBack_DynamicArray(void *DArray)

{

if (DArray == NULL)

{

return -1;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

int ret = eraseByPos_DynamicArray(DArray, dynamicarray->ArrayLen - 1);

return ret;

}

// 查看某个位置的值

void * GetByPos_DynamicArray(void *DArray, int Pos)

{

// 这儿没有做安全检查的原因是,因为在实际的数组中,我们访问一个不存在的值时可能导致程序崩溃,这儿也是这样的

DynamicArray *dynamicarray = (DynamicArray *)DArray;

return dynamicarray->Array[Pos];

}

查看某个数据在当前的数组中是否存在

int  GetByVal_DynamicArray(void *DArray, void *Val, COMPARE compare)

{

if (DArray == NULL)

{

return -1;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

for (int i = 0; i < dynamicarray->ArrayLen; ++i)

{

if (!compare(dynamicarray->Array[i], Val))

{

return i;

}

}

return -1;

}

// 遍历(打印当前的数组)

void Traversal_DynamicArray(void *DArray, TRAVERSAL traversal)

{

if (DArray == NULL)

{

return;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

printf("<……………………………………………………>\n");

for (int i = 0; i < dynamicarray->ArrayLen; ++i)

{

traversal(dynamicarray->Array[i]);

}

}

// 对当前的数组的释放

int Destroy__DynamicArray(void *DArray)

{

if (DArray == NULL)

{

return -1;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

if (dynamicarray->Array != NULL)

{

free(dynamicarray->Array);

dynamicarray->Array = NULL;

}

free(dynamicarray);

dynamicarray = NULL;

return 0;

}

一些其他功能:

// 得到数组的长度

int Size_DynamicArray(void *DArray)

{

if (DArray == NULL)

{

return 0;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

return dynamicarray->ArrayLen;

}

// 得到数组的容量

int Capacity_DynamicArray(void *DArray)

{

if (DArray == NULL)

{

return 0;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

return dynamicarray->Capacity;

}

数组的逆置

int Inverted_DynamicArray(void *DArray)

{

if (DArray == NULL)

{

return -1;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

for (int i = 0; i < dynamicarray->ArrayLen / 2; ++i)

{

void *temp = dynamicarray->Array[i];

dynamicarray->Array[i] = dynamicarray->Array[dynamicarray->ArrayLen - 1 - i];

dynamicarray->Array[dynamicarray->ArrayLen - 1 - i] = temp;

}

return 0;

}

// 数组的排序

int Sort__DynamicArray(void *DArray, COMPARE compare)

{

if (DArray == NULL)

{

return -1;

}

DynamicArray *dynamicarray = (DynamicArray *)DArray;

if (dynamicarray->ArrayLen == 1)

{

return 0;

}

Quick_Sort(dynamicarray->Array, 0, dynamicarray->ArrayLen - 1, compare);

return 0;

}

这个没有给出Quick_Sort(dynamicarray->Array, 0, dynamicarray->ArrayLen - 1, compare)函数,主要是因为这个值修改来自于快排,要相信自己也是可以的。

源码可能会被放到github上面。最近在培训时间学习怎么使用github,如果你有想关的操作的视频教程欢迎你分享给我!

谢谢!!

时间: 2024-08-06 11:35:14

通用型动态数组的总结的相关文章

int型动态数组总结

简单的数据结构之-int型动态数组 这个貌似没有参考可以借鉴,如果哪位有幸看到,请您给我说一下哈!再次感谢各位了! 想关的参看的资料来自某培训机构,我是参照动态数组写的 想关的介绍文章 C语言中文网:http://c.biancheng.net/cpp/html/2790.html 数组都有一个固定的长度,超出它的长度就无法再添加新的元素,但是动态数组可以动态的增加数组的长度,可以无限的插入数据. // 动态数组是一个不存在的数据类型,所以需要定义一个结构体来说明动态数组的类型,数组需要空间存储

C#定义动态数组(泛型)

C#代码中定义动态数组的时候,是很有讲究的.我们通常不知道我们需要多大空间,而且在数据之间的转化也是一个问题. 问题一: GUID类型无法转换为GUID[] 解答: 我们尝试的时候一般用的是数组: <span style="font-size:18px;"> Guid[] staff = new Guid[] { settingEvaluationBLL.LoadEnities(s => s.YzStaffEntityEvaluaterID.ID == Evaluat

Hive通用型自定义聚合函数(UDAF)

在使用hive进行数据处理时,经常会用到group by语法,但对分组的操作,hive没有mysql支持得好: group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator '分隔符']) hive只有一个collect_set内置函数,返回去重后的元素数组,但我们可以通过编写UDAF,来实现想要的功能. 编写通用型UDAF需要两个类:解析器和计算器.解析器负责UDAF的参数检查,操作符的重载以及对于给定的一组参数类型来查找

【足迹C++primer】40、动态数组

动态数组 C++语言定义了另外一种new表达式语法,可以分配并初始化一个对象数组.标准库中包含 一个名为allocator的类,允许我们将分配和初始化分离. 12.2.1 new和数组 void fun1() { int *pia=new int[2]; //pia指向第一个int //方括号中的大小必须是整型,但不必是常量 typedef int arrT[42]; //arrT表示42个int的数组类型 int *p=new arrT; //分配一个42个int的数组:p指向第一个int /

C++中关于[]静态数组和new分配的动态数组的区别分析

这篇文章主要介绍了C++中关于[]静态数组和new分配的动态数组的区别分析,很重要的概念,需要的朋友可以参考下 本文以实例分析了C++语言中关于[]静态数组和new分配的动态数组的区别,可以帮助大家加深对C++语言数组的理解.具体区别如下: 一.对静态数组名进行sizeof运算时,结果是整个数组占用空间的大小:因此可以用sizeof(数组名)/sizeof(*数组名)来获取数组的长度.int a[5]; 则sizeof(a)=20,sizeof(*a)=4.因为整个数组共占20字节,首个元素(i

二维数组指针及二维动态数组的分配问题

在我以前的文章中都有讲过关于数组指针及指针数组的相关问题,但是讲得不够深入,我后来后了别人写的博客后觉得人家的确实写得好, 也学到了不少东西,对以前的问题有深的领悟了,于是准备结合这些博客和文章再稍微深入一点讲讲这些问题.这些指针的问题是C语言中的基础与关键 而且一旦出现这些问题,不太好找bug的来源,有时候不得不借助反汇编. 参考文章: http://c.biancheng.net/cpp/html/476.html       C语言指针数组和数组指针 http://blog.csdn.ne

一维动态数组和二维动态数组的创建和使用

#include<stdio.h> #include<malloc.h> void main(){ int *a,n=10,i; /* calloc()函数的原型是:(void *)calloc(unsigned n,unsigned size) calloc()函数用于向系统动态申请n个,每个占sizege字节的内存单元,函数返回值为所申请的内存空间首地址 malloc和calloc主要区别在于,当系统的内存只剩下一些非常小的碎片时,用calloc函数设计的动态数组的时间效率优于

静态数组和动态数组

概念 数组在程序设计中应用十分广泛,可以用不同类型的数组来存储大量相同类型的数据.创建数组的方式一般有三种: 全局/静态范围的数组.局部变量数组.申请堆空间创建的数组.其中,全局/静态范围的数组以及局部变量数组都属于静态数组,从堆中申请空间建立的数组为动态数组. 静态数组和动态数组的区别 1.静态数组的大小是在编译期间就确定,并且分配的,其内存在使用结束后由计算机自动释放,效率高:动态数组是在程序运行时,由程序员根据实际需要从堆内存中动态申请的,使用结束后由程序员进行释放,效率低. 2.对静态数

C++ primer 第十二章笔记之 动态数组

new与数组 为了让new分配一个对象数组,必须在类型名之后跟[].在其中指明分配的数目; int *pia = new int [ get_size() ]; //[]内必须为整型,但不必是常量; typedef int arrT[24]; int * p = new arrT; //分配一个24个int的数组,p指向第一个int; 初始化,C++11:可用花括号{}; 动态分配一个空数组是合法的; 释放动态数组: delete p; delete [] pa; 智能指针与动态数组: 标准库提