数据结构之动态数组实现

          动态数组,是相对于静态数组而言。静态数组的长度是预先定义好的,在整个程序中,一旦给定大小后就无法改变。而动态数组则不然,它可以随程序需要而重新指定大小。动态数组的内存空间是从堆(heap)上分配(即动态分配)的。是通过执行代码而为其分配存储空间。当程序执行到这些语句时,才为其分配。程序员自己负责释放内存。
         为什么要使用动态数组?
在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。对于这种问题,用静态数组的办法很难解决。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数结合指针可以按需要动态地分配内存空间,来构建动态数组,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。
        动态数组与静态数组的对比
对于静态数组,其创建非常方便,使用完也无需释放,要引用也简单,但是创建后无法改变其大小是其致命弱点!
对于动态数组,其创建麻烦,使用完必须由程序员自己释放,否则严重会引起内存泄露。但其使用非常灵活,能根据程序需要动态分配大小。

         本章中对于动态数组的遍历使用到了迭代器操作,迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。
迭代器提供一些基本操作符:*、++、==、!=、=。这些操作和C/C++“操作array元素”时的指针接口一致。不同之处在于,迭代器是个所谓的复杂的指针,具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此,每一种容器型别都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套的方式定义于内部。因此各种迭代器的接口相同,型号却不同。这直接导出了泛型程序设计的概念:所有操作行为都使用相同接口,虽然它们的型别不同。
功能
迭代器使开发人员能够在类或结构中支持foreach迭代,而不必整个实现IEnumerable或者IEnumerator接口。只需提供一个迭代器,即可遍历类中的数据结构。当编译器检测到迭代器时,将自动生成IEnumerable接口或者IEnumerator接口的Current,MoveNext和Dispose方法。

特点
1.迭代器是可以返回相同类型值的有序序列的一段代码;
2.迭代器可用作方法、运算符或get访问器的代码体;
3.迭代器代码使用yieldreturn语句依次返回每个元素,yield break将终止迭代;
4.可以在类中实现多个迭代器,每个迭代器都必须像任何类成员一样有惟一的名称,并且可以在foreach语句中被客户端,代码调用如下所示:foreach(int x in SimpleClass.Iterator2){};
5.迭代器的返回类型必须为IEnumerable和IEnumerator中的任意一种;
6.迭代器是产生值的有序序列的一个语句块,不同于有一个 或多个yield语句存在的常规语句块;
7.迭代器不是一种成员,它只是实现函数成员的方式,理解这一点是很重要的,一个通过迭代器实现的成员,可以被其他可能或不可能通过迭代器实现的成员覆盖和重载
8.迭代器块在C#语法中不是独特的元素,它们在几个方面受到限制,并且主要作用在函数成员声明的语义上,它们在语法上只是语句块而已;
9.yield关键字用于指定返回的值。到达yieldreturn语句时,会保存当前位置。下次调用迭代器时将从此位置重新开始执行。 迭代器对集合类特别有用,它提供一种简单的方法来迭代不常用的数据结构(如二进制树)。
简介
迭代器是一种检查容器内元素并遍历元素的数据类型。

对于迭代器iterator.h头文件的实现如下:

  1 #ifndef _ITERATOR_H_
  2 #define _ITERATOR_H_
  3 
  4 typedef struct Iterator{
  5     void *ptr;    //指定的容器中元素的地址
  6     int index;    //迭代器当前容器中的下标
  7     int  size;    //迭代器所指向容器的有效元素的个数
  8 }Iterator;
  9 
 10 //正向迭代
 11 //iter是迭代器的存储实体
 12 //container是容器的地址
 13 
 14 #define FOREACH(iter,container)\
 15     for(container ->iter_head(&iter,container);\
 16     (iter).ptr;\
 17     container ->iter_next(&iter,container))
 18 
 19 #define foreach FOREACH
 20 
 21 //反向迭代
 22 #define REVERSE_FOREACH(iter,container)\
 23     for(container ->iter_tail(&iter,container);\
 24     (iter).ptr;\
 25     container ->iter_prev(&iter,container))
 26 
 27 #define reverse_foreach REVERSE_FOREACH
 28 
 29 #endif
~           

foreach 和 reverse_foreach分别为为正向和反向遍历.

本章中对于dynamic_array.h 的实现如下:

#ifndef _DYNAMIC_ARRAY_H_
#define _DYNAMIC_ARRAY_H_

#include "tools.h"
#include "iterator.h"

#define BASE_SIZE  (32)
typedef struct Array Array;
//动态数组的结构体
struct Array{
    void  **data;    //动态数组的存储实体
    int capacity;    //动态数组申请的总量
    int    count;    //动态数组当前有效元素的个数

    //1.释放函数指针
    void (*free)(const void *ptr);
    //2.匹配函数指针
    Boolean (*match)(const void *value1,const void *value2);
    //3.拷贝函数指针
    void *(*copy)(const void *src_value,void *dest_value);

    //插入删除操作
    //1.头插
    Boolean (*push_front)(Array *array,void *value);
    //2.尾插
    Boolean (*push_back)(Array *array,void *value);
    //3.头删
    Boolean (*pop_front)(Array *array);
    //4.尾删
    Boolean (*pop_back)(Array *array);


    //迭代器操作
    //1.指向动态数组的头部
    void *(*iter_head)(Iterator *iter,Array *array);
    //2.指向下一个元素的位置
    void *(*iter_next)(Iterator *iter,Array *array);
    //3.指向动态数组的尾部
    void *(*iter_tail)(Iterator *iter,Array *array);
    //4.指向动态数组的上一个元素
    void *(*iter_prev)(Iterator *iter,Array *array);
};

//定义动态数组的接口
Array   *init_array(int init_size);    //动态数组的初始化
void    destroy_array(Array **array);    //动态数组的销毁
void    array_clean(Array *array);    //动态数组的清零

//插入到指定下标的前边
Boolean  array_prev_insert(Array *array,int index,void *value);
//插入到指定下标的后边
Boolean  array_next_insert(Array *array,int index,void *value);


void *get_array_index(Array *array,int index);    //得到指定下标的元素
int   get_array_count(Array *array);    //得到动态数组的个数
Boolean get_array_front(Array *array ,void **value);    //得到头部元素
Boolean get_array_tail(Array *array,void **value);    //得到尾部元素
Boolean delete_index_value(Array *array,int index);    //删除指定下标元素
Boolean delete_range_value(Array *array,int left,int right);    //删除指定范围的下标元素
int  find_value(Array *array,void *value);    //查找指定元素的下标

#endif

dynamic_array.c对于接口的实现如下:

#include <stdio.h>
#include <stdlib.h>
#include "dynamic_array.h"

//动态数组的增长
static void array_grow(Array *array,int size);

//调整大小
static int adjust_size(int size);

//动态数组为满
static Boolean is_array_full(Array *array);


static void array_grow(Array *array,int size)
{
    //两种情况
    //1.初始化状态
    //2.数组空间不够进行扩展

    //10 -> 32
    //31 -> 32
    //32 -> 32
    //33 -> 64
    int adjust = 0;

    if(array ->capacity < size){
        //对申请的大小做向上取整(32整数倍)
        //
        //   35 % 32 = 3
        //   32 - 3  = 29
        //   35 + 29 = 64
        //
        adjust = adjust_size(size);
        array ->capacity = adjust;
        if(array ->data){
            array ->data = (void **)Realloc(array ->data,
                                    sizeof(void *) * adjust);
        }else{
            array ->data = (void **)Malloc(sizeof(void *) * adjust);

        }
    }
}
static int adjust_size(int size)
{
 //对申请的大小做向上取整(32整数倍)
 //
 //   35 % 32 = 3
 //   32 - 3  = 29
 //   35 + 29 = 64
 //
     return size + (BASE_SIZE - (size % BASE_SIZE));
}
static Boolean is_array_full(Array *array)
{
    return array ->capacity <= array ->count;
}

//1.头插
Boolean (array_push_front)(Array *array,void *value)
{
    array_prev_insert(array,0,value);    
}
//2.尾插
Boolean (array_push_back)(Array *array,void *value)
{
    if(array == NULL || value == NULL){
        return FALSE;
    }
    if(is_array_full(array)){
        array_grow(array,array ->capacity + BASE_SIZE);
    }
    array ->data[array ->count] = value;
    array ->count++;
   
    return TRUE;
}
//3.头删
Boolean (array_pop_front)(Array *array)
{
    void *delete = NULL;
    int i = 0;
    int move_count = 0;
    if(array == NULL || array ->count == 0){
        return FALSE;
    }
    //删除操作
    array ->count--;
    delete = array ->data[0];

    if(array ->free){
        array ->free(delete);
    }

    for(i = 0,move_count = array ->count;i < move_count; ++i){
        array ->data[i] = array ->data[i + 1];
    }
    array ->data[i] = NULL;
    return TRUE;
}
//4.尾删
Boolean (array_pop_back)(Array *array)
{
    void *delete = NULL;
    if(array == NULL || array ->count == 0){
        return FALSE;
    }

    array ->count--;
    delete = array ->data[array ->count];

    if(array ->free){
        array ->free(delete);
    }
    array ->data[array ->count] = NULL;
    return TRUE;
}


//迭代器操作
//1.指向动态数组的头部
void *(array_iter_head)(Iterator *iter,Array *array)
{
    if(iter == NULL || array == NULL){
        return NULL;
    }
    iter ->index = 0;
    iter ->size = array ->count;
    if(array ->data == NULL || array ->count == 0){
        iter ->ptr = NULL;
    }else{
        iter ->ptr = array ->data[0];
    }
    return iter ->ptr;
}
//2.指向下一个元素的位置
void *(array_iter_next)(Iterator *iter,Array *array)
{
    if(iter == NULL || array == NULL){
        return NULL;
    }
    iter ->index++;
    if(iter ->index >= iter ->size){
        iter ->ptr = NULL;
    }else{
        iter ->ptr = array ->data[iter ->index];
    }
    return iter ->ptr;
}
//3.指向动态数组的尾部
void *(array_iter_tail)(Iterator *iter,Array *array)
{
    if(iter == NULL || array == NULL){
        return NULL;
    }
    iter ->index = array ->count - 1;
    iter ->size = array ->count;
    if(array ->data == NULL || array ->count == 0){
        iter ->ptr = NULL;
    }else{
        iter ->ptr = array ->data[iter ->index];
    }
    return  iter ->ptr;
}
//4.指向动态数组的上一个元素
void *(array_iter_prev)(Iterator *iter,Array *array)
{
    if(iter == NULL || array == NULL){
        return NULL;
    }
    iter ->index--;
    if(iter ->index < 0){
        iter ->ptr = NULL;
    }else{
        iter ->ptr = array ->data[iter ->index];
    }
    return  iter ->ptr;
    
}

Array   *init_array(int init_size)    //动态数组的初始化
{
    Array *array = (Array *)Malloc(sizeof(Array));

    //初始化赋值
    array ->free = NULL;
    array ->match = NULL;
    array ->copy = NULL;

    //头删、尾删、头插、尾插
    array ->push_front = array_push_front;
    array ->push_back = array_push_back;
    array ->pop_front = array_pop_front;
    array ->pop_back = array_pop_back;

    //迭代器操作
    //指向头部、指向下一个、指向尾部、指向是上一个
    array ->iter_head = array_iter_head;
    array ->iter_tail = array_iter_tail;
    array ->iter_next = array_iter_next;
    array ->iter_prev = array_iter_prev;

    array ->count = 0;
    array ->capacity = 0;
    array ->data = NULL;
    if(init_size > 0){
        array_grow(array,init_size);
    }
    return array;
}
void    destroy_array(Array **array)    //动态数组的销毁
{
    if(array == NULL || *array == NULL){
        return ;
    }
    //销毁步骤
    //1.先销毁数组元素所指向的空间(如果需要销毁的话)
    //2.销毁array ->data
    //3.销毁array控制信息

    array_clean(*array);
    free((*array) ->data);
    free(*array);
    *array = NULL;
}
void    array_clean(Array *array)    //动态数组的清零
{
    delete_range_value(array,0,array->count - 1);
} 

//插入到指定下标的前边
Boolean  array_prev_insert(Array *array,int index,void *value)
{
    int i = 0;
    if(array == NULL || value == NULL 
       || index < 0 || index >= array ->count){
        return FALSE;
    }
    if(is_array_full(array)){
        array_grow(array, array->capacity + BASE_SIZE);
    }
    for(i = array ->count;i > index;--i){
        array ->data[i] = array ->data[i - 1];
    }
    array ->data[i] = value;
    array ->count++;
    return TRUE;
}
//插入到指定下标的后边
Boolean  array_next_insert(Array *array,int index,void *value)
{
    int i = 0;
    if(array == NULL || value == NULL 
      || index < 0 || index >= array ->count){
        return FALSE;
    }
    if(is_array_full(array)){
        array_grow(array, array->capacity + BASE_SIZE);
    }
    for(i = array ->count;i > index + 1;--i){
        array ->data[i] = array ->data[i - 1];
    }
    array ->data[i] = value;
    array ->count++;
    return TRUE;
    
}


void *get_array_index(Array *array,int index)    //得到指定下标的元素
{
    if(array == NULL || index < 0 || index >= array ->count){
        return NULL;
    }
    return array ->data[index];
}
int   get_array_count(Array *array)    //得到动态数组的个数
{
    if(array == NULL){
        return -1;
    }
    return array ->count;
}
Boolean get_array_front(Array *array ,void **value)    //得到头部元素
{
    if(array == NULL || array ->count == 0){
        return FALSE;
    }
    if(value){
        *value = array ->data[0];
        return TRUE;
    }
    return FALSE;
}
Boolean get_array_tail(Array *array,void **value)    //得到尾部元素
{
    if(array == NULL || array ->count == 0){
        return FALSE;
    }
    if(value){
        *value = array ->data[array ->count - 1];
        return TRUE;
    }
    return FALSE;
}
Boolean delete_index_value(Array *array,int index)    //删除指定下标元素
{
    delete_range_value(array,index,index);
}
Boolean delete_range_value(Array *array,int left,int right)    //删除指定范围的下标元素
{
    int i = 0;
    int j = 0;
    int move_count = 0;
    if(array == NULL || left < 0 || right >= array ->count
       || left > right || array ->count == 0){
        return FALSE;
    }
    //先处理删除操作
    for(i = left;i < right;++i){
        if(array ->free){
            array ->free(array ->data[i]);
        }
        array ->data[i] = NULL;
    }
    //在处理移动操作
    move_count = array ->count;
    for(i = left,j = right + 1;j < move_count;++i,++j){
        array ->data[i] = array ->data[j];
        array ->data[j] = NULL;
    }
    array ->count -= (right - left) - 1;
    return TRUE;
}
int  find_value(Array *array,void *value)    //查找指定元素的下标
{
    Iterator iter = {0};
    if(array == NULL || value == NULL){
        return -1;
    }
    if(array ->match){
        foreach(iter,array){
            if(array ->match(iter.ptr,value)){
                return iter.index;
            }
        }
    }else{
        foreach(iter,array){
            if(iter.ptr == value){
                return iter.index;
            }
        }
    }
    return -1;
}

在dynamic_array.h 中结构体对于插入和删除进行了封装.


工具文件tools.h和tools.c的实现如下:
tools.h

 1 #ifndef _TOOLS_H_
  2 #define _TOOLS_H_
  3 
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 //定义布尔类型
  7 #define TRUE   (1)
  8 #define FALSE  (0)
  9 
 10 
 11 typedef unsigned char Boolean;
 12 
 13 //定义接口
 14 void *Malloc(size_t size);
 15 void *Realloc(void * ptr,size_t size);
 16 void print_int(void *value);
 17 #endif

tools.c

 1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include "tools.h"
  4 
  5 void *Malloc(size_t size)
  6 {
  7     void *result = malloc(size);
  8     if(result == NULL){
  9         fprintf(stderr,"the memory is full!\n");
 10         exit(1);
 11     }
 12     return result;
 13 }
 14 
 15 void *Realloc(void * ptr,size_t size)
 16 {
 17     void *result = realloc(ptr,size);
 18     if(result == NULL){
 19         fprintf(stderr,"the memory is full!\n");
 20         exit(1);
 21     }
 22     return result;
 23 }
 24 void print_int(void *value)
 25 {
 26     int *p = (int *)value;
 27     printf("%5d",*p);
 28 }


测试程序如下:
#include <stdio.h>
#include <stdlib.h>
#include "dynamic_array.h"
#include "tools.h"
#include "iterator.h"

int main(int argc,char **argv)
{
    Array *array = NULL;
    Iterator iter = {0};
    int arr[] = {3,2,5,8,4,7,6,9};
    int arr_length = sizeof(arr) / sizeof(arr[0]);
    int  i = 0;

    array = init_array(5);    //初始化动态数组

    for(i = 0;i < arr_length;++i){
        array ->push_back(array,&arr[i]);
    }
    
    //打印动态数组元素
    foreach(iter,array){
        print_int(iter.ptr);
    }
    printf("\n");
    
    //头部删除
    for(i = 0;i < 3;++i){
        array ->pop_front(array);
    }

    //打印动态数组元素
    foreach(iter,array){
        print_int(iter.ptr);
    }
    printf("\n");
    
    destroy_array(&array);
    return 0;
}

其实验结果和内存检测如下图所示:



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值