栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

自制简易可变数组

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自制简易可变数组

自制可变数组 具有的功能:
  1. 初始化
  2. 判断是否为空
  3. 判断是否满
  4. 展示数组
  5. 在末尾追加值(若数组已满可自动增长)
  6. 在中间插入值
  7. 删除指定位置的值
  8. 倒置数组
  9. 整理数组
搭建(diy)过程
  1. 自定义一个结构类型 Arr,包含一个指针 pBase、数组总长度 len、数组有效长度 cnt;
typedef struct {
  int *pBase;
  int len;
  int cnt;
} Arr;

int main(void)
{
  Arr arr;
  return 0;
}
  • 指针 pBase 就类似普通数组中数组变量名的作用,对其进行操作就可以获得数组中的任一元素
  1. 有了结构类型 Arr 后,若只是单纯命名一个 Arr 变量,这个变量是不包含任何有效信息的,这时其中的pBase 没有指向任何有效区域,而且数组总长度 len 也没有给出,所以需要对其进行初始化,编写初始化函数 init_arr();
void init_arr(Arr * pArr, int length);

int main(void)
{
	Arr arr;
    int length = 2;
	init_arr(&arr, length);
    return 0;
}

void init_arr(Arr * pArr, int length)
{
	pArr->pBase = (int *)malloc(sizeof(int) * length); 
//使 pBase 指向一片长度为 length * sizeof(int)的空间,即此时 arr 中可以装 length 个 int                                  
	if ( pArr->pBase == NULL ) // 若 malloc 函数返回 NULL 值,说明内存不足,此时终止程序 
	{
		printf("动态内存分配失败!!!n");
		exit(-1); //终止整个程序 
	}
	else
	{
		pArr->len = length; //将数组总长度保存在 Arr 类型的 len 中
		pArr->cnt = 0;      //将数组有效长度保存在 Arr 类型的 cnt 中,初始为 0
	}
	return;
}
  1. 有了初始化的功能后,如果要查看该数组,采用循环的方式就很不方便了,此时可以定义一个 show_arr() 函数,使其直接能够展示给用户看,需要注意的是,如果数组为空,需要告诉用户,这时可以用一个返回bool 值的 is_empty() 函数来完成判断;
bool is_empty(Arr * pArr);
void show_arr(Arr * pArr);

int main(void)
{
   Arr arr;
   int length = 2;
   init_arr(&arr, length);
   show_arr(&arr);
   
   return 0;
}

bool is_empty(Arr * pArr)
{
   if ( pArr->cnt == 0 ) // 对数组当前的有效数字进行判断,若为 0,则数组为空
   {
   	return true;
   }
   else
   {
   	return false;
   }
}

void show_arr(Arr * pArr)
{
   if ( is_empty(pArr) )
   {
   	printf("还没有向数组添加任何元素!!!n");
   }
   else
   {
   	for ( int i=0;icnt;i++ )
   	{
   		printf("%d ", pArr->pBase[i]); 
           // pArr->pBase[i] <<==>> *pArr->pBase
   	}
   	printf("n");
   }
}
  1. 到现在为止,还没有办法向数组添加任何元素,先定义一个简单的 append_arr() 函数,其作用是在数组的末尾添加一个元素,这时需要注意,如果数组的空间已满,就无法简单的在最后插入一个元素了,而需要增大数组空间,这里使用的是申请另一块大内存的方式来实现”自动扩容“功能,还需要一个判断数组是否已满的函数;
bool is_full(Arr * pArr);
void append_arr(Arr * pArr, int val); 

const int unit = 4; //定义一个常量 unit,代表数组空间不够时增长的大小

int main(void)
{
	Arr arr;
    int length = 2;
	init_arr(&arr, length);
    append_arr(&arr, 2);
    append_arr(&arr, 7);
    show_arr(&arr);
    
    return 0;
}

bool is_full(Arr * pArr)
{
	if ( pArr->cnt < pArr->len ) 
        // 将当前数组有效长度与总长度进行比较,若 cnt>=len 已满
	{
		return false;
	}
	else
	{
		return true;
	}
}

void append_arr(Arr * pArr, int val)
{
    // val 代表添加元素的值
	if ( is_full(pArr) )
	{
		int * p;
		int length = pArr->len + unit;
		p = (int *)malloc(sizeof(int) * length); 
        // 申请另一块比原数组空间大 1 个的 unit 的数组
		if ( p == NULL ) // 若 malloc 函数返回 NULL 值,
		                 // 说明内存不足,此时终止程序 
		{
			printf("动态内存分配失败!!!n");
			exit(-1); //终止整个程序 
		}
		else
		{
			for ( int i=0;icnt;i++ )
			{
				p[i] = pArr->pBase[i];
                // 将原数组空间中的值赋值给新数组空间
			}
			free(pArr->pBase); 
            // 完成赋值后,将原数组空间释放,避免占用系统空间
			pArr->pBase = p; 
            // 将新申请到的数组空间赋值给原数组的指针,即使得原数组的指针指向新的一片大空间
			pArr->pBase[pArr->cnt++] = val; 
            // 将新添加的元素放到数组最后位置,并将有效长度 cnt++
			pArr->len = length;
            // 更新数组长度
		}
	}
	
	else
	{
		pArr->pBase[pArr->cnt++] = val;
        // 将新添加的元素放到数组最后位置,并将有效长度 cnt++
	}
	return;
}
  1. 有了在末尾添加元素的功能后,感觉还需要一个在数组中间插入元素的功能,不然感觉缺了一块,于是来定义一个 insert_arr() 函数实现此功能,与 append_arr() 函数相似,需要在数组已满时”自动扩容“;
void insert_arr(Arr * pArr, int pos, int val);

int main(void)
{
   Arr arr;
   int length = 2;
   init_arr(&arr, length);
   append_arr(&arr, 2);
   append_arr(&arr, 7);
   insert_arr(&arr, 2, 3);
   show_arr(&arr);
   
   return 0;
}

void insert_arr(Arr * pArr, int pos, int val)
{
   // pos 代表插入元素的位置,从 1 开始
   // val 代表插入元素的值
   if ( is_full(pArr) )
   // 如果数组已满,需要申请另一片大空间,对数组”扩容“,并分两次(插入位置前后)将原数组元素     // 写入新的数组空间
   {
   	int * p;
   	int length = pArr->len + unit;
   	p = (int *)malloc(sizeof(int) * length);
   	if ( p == NULL ) // 若 malloc 函数返回 NULL 值,
   	                 // 说明内存不足,此时终止程序 
   	{
   		printf("动态内存分配失败!!!n");
   		exit(-1); //终止整个程序 
   	}
   	else
   	{
   		for ( int i=0;ipBase[i];
               // 将原数组元素位于插入位置之前的元素赋值到新的数组内存中
   		}
   		p[pos-1] = val;
           // 将 val 的值赋给对应位置
   		pArr->cnt++;
           // 原数组 cnt 的值加 1,即有效数字加一
   		for ( int i=pos;icnt;i++ )
   		{
   			p[i] = pArr->pBase[i-1]; 
               // 将原数组元素位于插入位置之后的元素赋值到新的数组内存中
   		}
   		free(pArr->pBase); 
           // 完成赋值后,将原数组空间释放,避免占用系统空间
   		pArr->pBase = p; 
           // 将新申请到的数组空间赋值给原数组的指针,即使得原数组的指针指向新的一片大空间
   		pArr->len = length;
           // 更新数组有效长度
           
   	}
   }
   else
   // 若函数还有空间,只需要将数组中位于插入位置之后的值向后移一个内存,给对应位置留空即可
   {
   	for ( int i=pArr->cnt;i>pos-1;i-- )
   	{
   		pArr->pBase[i] = pArr->pBase[i-1];
           // 将原数组元素位于插入位置之后的元素往后移位
   	}
   	pArr->pBase[pos-1] = val;
       // 将 val 的值赋给对应位置
   	pArr->cnt++;
       // 原数组 cnt 的值加 1,即有效数字加一
   }
   return;
}

  1. 此时数组已经可以随意添加任意的元素了,这就足够了吗?当然不够,光增不减可不行,还需要一个删除元素的功能,delete_arr() 可以删除指定位置的元素,并告诉用户删除掉的值是多少以及数组剩下多少个有效值;
void delete_arr(Arr * pArr, int pos);

int main(void)
{
   Arr arr;
   int length = 2;
   init_arr(&arr, length);
   append_arr(&arr, 2);
   append_arr(&arr, 7);
   insert_arr(&arr, 2, 3);
   show_arr(&arr);
   delete_arr(&arr, 3);
   show_arr(&arr);
   
   return 0;
}

void delete_arr(Arr * pArr, int pos)
{
   int val;
   if ( is_empty(pArr) )
   // 删除前先判断数组里面有没有值,没有值可没办法删
   {
   	printf("数组为空!!!删除失败n");
   }
   else
   {
   	if ( pos <= pArr->cnt)
       // 如果有值还需要判断删除的位置有没有大于数组有效长度,如果这个位置比数组有效长度还长         // 也没法删除
   	{
   		val = pArr->pBase[pos-1]; 
           // 先将这个值保存到变量 val 中,之后要告诉用户
   		for ( int i=pos-1;icnt-1;i++ )
   		{
   			pArr->pBase[i] = pArr->pBase[i+1];
               // 直接将位于这个值之后的值向前移动一位,以此覆盖掉那个位置的值
   		}
   		pArr->cnt--;
           // 删除掉了一个值,所以有效长度减一
   		printf("删除掉的数字是 %d, 数组还剩下 %d 个有效值n",val,pArr->cnt);
           // 告知用户
   	}
   	else
   	{
   		printf("删除位置大于当前数组有效长度!!!删除失败n");
   	}
   }
   return;
}
  1. 有了基本的增减元素功能之后,还需要一些进阶功能才能使得数组变得易用,先来个倒置的功能吧,inverse_arr() 函数可以将当前数组的有效值顺序取反,由”正序变为反序“;
void inverse_arr(Arr * pArr);

int main(void)
{
   Arr arr;
   int length = 2;
   init_arr(&arr, length);
   append_arr(&arr, 2);
   append_arr(&arr, 7);
   insert_arr(&arr, 2, 3);
   show_arr(&arr);
   delete_arr(&arr, 3);
   inverse_arr(&arr);
   show_arr(&arr);
   
   return 0;
}

void inverse_arr(Arr * pArr)
{
   // 倒置函数将由一个倒置算法实现:
   // 其中 i 为数组初始序列,即为 0, j 为数组最后序列,为 cnt-1
   // t 用来保存值,理解成 temp 
   int t;
   int i = 0;
   int j = (pArr->cnt)-1;
   while ( i < j )
   // 用 while 循环来进行这个过程,整个过程如下:
   // 将数组头部的值赋给 t ,将数组尾部的值赋给数组头部,将 t 的值赋给数组尾部
   // 实现一次交换,随后将头部指针向后移一位,尾部指针向前移一位,重复上述过程,直到前面的指针大于后面的指针就停止整个过程
   {
   	t = pArr->pBase[i];
   	pArr->pBase[i] = pArr->pBase[j];
   	pArr->pBase[j] = t;
   	i++;
   	j--;
	}
	return;
}
  1. 有了各种花里胡哨的功能之后,数组成功的被用户给弄乱了,这时候又需要整理整个数组,sort_arr() 函数可以将数组按照从小到大的顺序排列,排序算法后面学了再来补充
void sort_arr(Arr * pArr);

int main(void)
{
   Arr arr;
   int length = 2;
   init_arr(&arr, length);
   append_arr(&arr, 2);
   append_arr(&arr, 7);
   insert_arr(&arr, 2, 3);
   show_arr(&arr);
   delete_arr(&arr, 3);
   inverse_arr(&arr);
   show_arr(&arr);
   sort_arr(&arr);
   
   return 0;
}
void sort_arr(Arr * pArr)
{
   // ”首值比小“算法
   int t;
   for ( int i=0;icnt;i++ )
   {
   	for ( int j=i+1;jcnt;j++ )
   	{
   		if ( pArr->pBase[j] < pArr->pBase[i] )
   		{
   			t = pArr->pBase[i];
   			pArr->pBase[i] = pArr->pBase[j];
   			pArr->pBase[j] = t;
   		}
   	}
   }
}
  1. 到这里我自己 diy 的一个简单的数组就完成了,期待链表的学习,因为这个可变数组的缺陷很明显,如果数组太大的话,申请一块内存再重写的方式很鸡肋,甚至在释放掉原数组之前还可能造成内存占用过大!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1012233.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号