数据结构7.动态数组

来源:互联网 发布:山西证券交易软件 编辑:程序博客网 时间:2024/05/21 10:57

引言:

我们之前提到过 数组(Array),是一种数据结构,是数据元素(elements)的集合。

数组的特点:

//数组的缺点:////    1.一旦数组定义,则大小固定,无法进行修改(数组的大小)。//    2.数组插入和删除的效率太低,时间复杂度O(n)。//    // 数组的优点://    //    1.下标访问,速度快,时间复杂度是O(1)

数组的定义:

//方法1int array1[10] = {0};    //方法2int array2[] = {12, 23, 34, 45, 56, 67, 78};  //方法3int *array3 = NULL;array3 = (int *)malloc(sizeof(int) * 100);   if(array3 != NULL){     fprintf(stderr, "the memory is full!\n");     exit(1);}

当初,我们说array1和array2都在定义时直接分配了栈上的内存空间;
而array3是一个int类型的指针,指向我们在堆上用malloc分配的4bytes ×100 = 400 bytes大小的空间。

普通情况下这样数组虽然在O(1)的时间复杂度访问下标进行数据存取查找,可是一般数组定义后,大小不能够进行动态变化,且插入删除效率过低,时间复杂度为O(n).
当初,为了弥补这些不足,我们又学习到了链表。而链表失去了很多数组的优点。
那怎么样才可以兼顾数组和链表的优点呢?今天我们将要学习动态数组。动态数组,是一种可以在任何时候改变大小的数组裝置。

一、动态数组基

动态数组是指在编译时不能确定数组长度,程序在运行时需要动态分配内存空间的数组。

我们要怎么样为数组分配到用来存储数据的空间呢。

NAME       malloc, free, calloc, realloc - allocate and free dynamic memorySYNOPSIS       #include <stdlib.h>       void *malloc(size_t size);       void free(void *ptr);       void *calloc(size_t nmemb, size_t size);       void *realloc(void *ptr, size_t size);
  1. void *malloc(size_t size);
    malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。

  2. void free(void *ptr);
    释放malloc(或calloc、realloc)函数给指针变量分配的内存空间的函数,释放申请的动态内存。
    使用后该指针变量一定要重新指向NULL,防止野指针出现,有效规避误操作。(另:对于free(p)这句语句,如果p 是NULL 指针,那么free 对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。)

  3. void *calloc(size_t nmemb, size_t size);
    在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。
    一般使用后要使用 free(起始地址的指针) 对内存进行释放,不然内存申请过多会影响计算机的性能,以至于得重启电脑。如果使用过后不清零,还可以使用指针对该块内存进行访问。

  4. void *realloc(void *ptr, size_t size);
    realloc函数功能为先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域,同时返回新分配的内存区域的首地址,即重新分配存储器块的地址。
  1. 我们看到用malloc()可以自己在堆上定义大小分配的空间,所以我们可以用malloc()为我们提供分配内存的方法。
  2. 如果已分配的内存不够我们可以使用relloc()函数,再次申请内存。

于是,照常我们将这些需要经常使用的函数,放入工具类定义:
tools.h

#ifndef _TOOLS_H_#define _TOOLS_H_#include <stdio.h>#include <stdlib.h>#include <string.h>//工具类接口void *Malloc(size_t size);void swap(void *a, void *b, int length);void *Realloc(void *ptr, size_t size);#endif

tools.c

#include "tools.h"void *Malloc(size_t size){    void *result = malloc(size);    if(result == NULL){        fprintf(stderr, "the memory is full!\n");        exit(1);    }    return result;}void swap(void *a, void *b, int length){    void *temp = Malloc(length);    memcpy(temp, a, length);     memcpy(a, b, length);     memcpy(b, temp, length);        free(temp);}void *Realloc(void *ptr, size_t size){    void *result = realloc(ptr, size);    if(result == NULL)    {        fprintf(stderr, "the memory is full !\n");        exit(1);    }    return result;}

照例可以使用迭代器:

iterator.h

#ifndef _ITERATOR_H_#define _ITERATOR_H_typedef struct Iterator{    void   *ptr;    int   index;    int    size;}Iterator;typedef Iterator iter;/* *正向迭代器 * container(list、array、stack)容器 */#define FOREACH(iter, container) \    for(container->iter_head(&(iter), container); \    (iter).ptr; \    container->iter_next(&(iter), container))#define foreach FOREACH#define FOREACH_REVERSE(iter, container) \    for(container->iter_tail(&(iter), container); \    (iter).ptr; \    container->iter_prev(&(iter), container))#define foreach_reverse FOREACH_REVERSE#endif

二、动态数组定义

dynamic_array.h

#ifndef _ARRAY_H_#define _ARRAY_H_#include "iterator.h"#define TRUE       (1)#define FALSE      (0)#define MODE_SIZE  (32)#define ZERO       (0)typedef unsigned char Boolean;typedef struct Array Array;struct Array{    void    **data;    //1.存储实体    int   capacity;    //2.动态数组申请大小    int      count;    //3.当前元素个数    //4.拷贝函数指针    void *(*copy)(void *src_value);    //5.匹配函数指针    Boolean (*match)(void *value1, void *value2);    //6.释放函数指针    void (*free)(void *ptr);    //7.头部插入    Boolean (*push_front)(Array *array, void *value);    //8.尾部插入    Boolean (*push_back)(Array *array, void *value);    //9.头部删除    Boolean (*pop_front)(Array *array);    //10.尾部删除    Boolean (*pop_back)(Array *array);    //    //迭代器操作    //11.指向数组头部的位置    void *(*iter_head)(Iterator *iter, Array *array);    //12.指向数组尾部的位置    void *(*iter_tail)(Iterator *iter, Array *array);    //13.指向后一个元素的位置    void *(*iter_next)(Iterator *iter, Array *array);    //14.指向前一个元素的位置    void *(*iter_prev)(Iterator *iter, Array *array);};//动态数组接口//1.初始化Array *init_array(int init_size);//2.销毁void destroy_array(Array **array);//3.清空void clean_array(Array *array);//4.插入到指定下标的前面Boolean array_insert_prev(Array *array,                         int index, void *value);//5.插入到指定下标的后面Boolean array_insert_next(Array *array,                         int index, void *value);//6.得到数组个数int get_array_count(Array *array);//7.得到指定下标元素void *get_index_value(Array *array, int index);//8.删除指定下标元素Boolean delete_index_value(Array *array, int index);//9.删除指定下标范围的元素Boolean delete_range_value(Array *array, int begin, int end);//10.查找指定元素的下标int find_array_value(Array *array, void *value);#endif

三、动态数组接口实现

dynamic_array.c

#include "dynamic_array.h"#include "tools.h"//前插、尾插、前删、尾删、static Boolean array_push_front(Array *array, void *value);static Boolean array_push_back(Array *array, void *value);static Boolean array_pop_front(Array *array);static Boolean array_pop_back(Array *array);//迭代器 头、尾、下一个、前一个static void *array_iter_head(Iterator *iter, Array *array);static void *array_iter_tail(Iterator *iter, Array *array);static void *array_iter_next(Iterator *iter, Array *array);static void *array_iter_prev(Iterator *iter, Array *array);//封装数组增长函数static void array_grow(Array *array, int size);static int  adjust_size(int size);//1. 数字调整static int  adjust_size(int size){    //MODE_SIZE == 32    size += (MODE_SIZE -1);    //100 -> 100 +31    size /= (MODE_SIZE);       //131 -> 131 /32 == 4    size *= (MODE_SIZE);       //4   -> 4 * 32  == 128                               //将其size增长到离size最近的32的倍数处    return size;}//2.调整数组大小static void array_grow(Array *array, int size){    int adjust = 0;    if(array->capacity < size)    {        adjust = adjust_size(size); //增长        array->capacity = adjust;        if(array->data != NULL)        {            array->data = Realloc(array->data,                              sizeof(void *)*adjust);        }        else        {            array->data = Malloc(sizeof(void *)*adjust);        }    }}//数组的插入删除操作//1.前插static Boolean array_push_front(Array *array, void *value){    return array_insert_prev(array, 0, value);}//2.尾插static Boolean array_push_back(Array *array, void *value){    if(array ==NULL || value == NULL)    {        return FALSE;    }    //如果数组容量不够,增长    if(array->count >= array->capacity)    {        array_grow(array, array->count + MODE_SIZE);    }    array->data[array->count] = value ;    array->count ++;    return TRUE;}//3.前删static Boolean array_pop_front(Array *array){    int i =0 ;    void *delete = NULL;    if(array == NULL || array->count == ZERO)    {        return FALSE;     }    array->count -- ;    delete = array->data[0];    if(array->free != NULL)    {        array->free(delete);    }    while(i < array->count)    {        array->data[i] = array->data[i+1];        ++i;    }    array->data[i] = NULL;    return TRUE;}//4.尾删static Boolean array_pop_back(Array *array){    void *delete = NULL;    if(array == NULL || array->count == ZERO)    {        return FALSE;     }    array->count -- ;    delete = array->data[array->count];    if(array->free != NULL)    {        array->free(delete);    }    array->data[array->count] = NULL;    return TRUE;}//迭代器操作接口//1. 迭代器头static 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 == ZERO)    {        iter->ptr = NULL;    }    else    {        iter->ptr = array->data[0];    }    return iter->ptr;}//2. 迭代器指向尾static 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 == ZERO)    {        iter->ptr = NULL;    }    else    {        iter->ptr = array->data[iter->index];    }    return iter->ptr;}//3. 迭代器 只想下一个数组元素static void *array_iter_next(Iterator *iter, Array *array){    if(iter == NULL || array == NULL)    {        return NULL;    }    iter->index ++;    iter->size = array->count;    if( iter->index >= iter->size)    {        iter->ptr = NULL;    }    else    {        iter->ptr = array->data[iter->index];    }    return iter->ptr;}//4. 迭代器 指向前一个数组元素static void *array_iter_prev(Iterator *iter, Array *array){    if(iter == NULL || array == NULL)    {        return NULL;    }    iter->index --;    iter->size = array->count;    if( iter->index <= ZERO)    {        iter->ptr = NULL;    }    else    {        iter->ptr = array->data[iter->index];    }    return iter->ptr;}//动态数组接口//1.动态数组初始化Array *init_array(int init_size){    Array *array = (Array *)Malloc(sizeof(Array));    //对控制信息成员进行初始化    array->count = 0;    //数组元素拷贝、比较、释放指针初始化为NULL    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->data = NULL;    array->capacity = 0;    if(init_size > 0)    {        array_grow(array, init_size);    }    return array;}//2.动态数组的销毁void destroy_array(Array **array){    //释放数组元素对应的空间    //释放data    //释放array    if(array == NULL)    {        return ;    }    delete_range_value(*array, 0, get_array_count(*array));    free(*array);    *array = NULL;}//3.动态数组清空void clean_array(Array *array){    if(array == NULL)    {        return ;    }    int i = 0 ;    while(i < array->count)    {        array->data[i] =  NULL;        ++i;    }}//4.插入到指定下标的前面Boolean array_insert_prev(Array *array, int index, void *value){    int i = 0;    if(array == NULL || value == NULL                     || index > get_array_count(array))    {        return FALSE;    }    //如果数组容量不够,增长    if(array->count+1 >= array->capacity)    {        array_grow(array, array->count + MODE_SIZE);    }    i = array->count;    //index及以后的元素向后推移    while(i > index)    {        array->data[i] = array->data[i-1];        --i;    }    //插入元素    array->count ++;    array->data[i] = value;    return TRUE;}//5.插入到指定下标的后面Boolean array_insert_next(Array *array,                         int index, void *value){    int i = 0;    if(array == NULL || value == NULL                     || index > get_array_count(array))    {        return FALSE;    }    //如果数组容量不够,增长    if(array->count+1 >= array->capacity)    {        array_grow(array, array->count + MODE_SIZE);    }    i = array->count;    //index及以后的元素向后推移,从后向前防止被覆盖    while(i > index)    {        array->data[i] = array->data[i-1];        --i;    }    //插入元素    array->count ++;    array->data[i] = value;    return TRUE;}//6.得到数组个数int get_array_count(Array *array){    if(array == NULL)    {        return -1;    }    return array->count;}//7.得到指定下标元素void *get_index_value(Array *array, int index){    if(array == NULL || index > get_array_count(array))    {        return NULL;    }    return array->data[index];}//8.删除指定下标元素Boolean delete_index_value(Array *array, int index){    int i = 0;    if(array == NULL || index > get_array_count(array))    {        return FALSE;    }    i = index;    //数组元素的移动,将其覆盖    while(i < array->count)    {        array->data[i] = array->data[i+1];        ++i;    }    //删除最后一个    if(array->free != NULL)    {        free(array->data[array->count]);    }    array->data[array->count] = NULL;    array->count --;    return TRUE;}//9.删除指定下标范围的元素Boolean delete_range_value(Array *array, int begin, int end){#if 1    int i = begin;    int diff = end - begin + 1;    int count = get_array_count(array);// 0 1 2 3 4 5 6 7 8 9 //     x x x           count:10  begin:2    end:4   diff:3// 0 1 5 6 7 8 9 x x x    if(array == NULL || begin > count || begin < 0 || end < 0         || end > count || diff < 0 )    {        return FALSE;    }    //后面diff个元素向前推移    while(i < count-diff)    {        array->data[i] = array->data[i+diff];        ++i;    }    if(array->free != NULL)    {        i = array->count;        while(i-- > count - diff)        {            free(array->data[i]);            array->data[i] = NULL;        }    }    array->count -= diff;    return TRUE;#endif}//10.查找指定元素的下标int find_array_value(Array *array, void *value){    int i = 0 ;    int count = get_array_count(array);    //printf("array_count:%d\n",count);    if(array == NULL || value == NULL)    {        return -1;    }    #if 1    //这里通过元素是否相同做比较    while(i++ < count)    {        if(*((int *)(&array->data[i])) == *((int *)value))        {            return i;        }    }    //或者通过匹配指针函数match    #else    for(i = 0 ; i < count; ++i)    {        if(array->match!=NULL)        {            if(array->match(array->data[i], value))            {                return i;            }        }        else        {            if(array[data[i] == value)            {                return i;            }        }    }    return -1;}

四、函数功能实现

文件结构:

├── dynamic_array├── dynamic_array.c├── dynamic_array.h├── iterator.h├── main├── main.c├── tools.c└── tools.h

main.c

#include <stdio.h>#include "iterator.h"#include "dynamic_array.h"int main(int argc, char **argv){    int i = 0;    Array *array= init_array(30);    int a[] = {1, 2, 3, 4, 5};    int length = sizeof(a)/sizeof(a[0]);    for(i = 0; i < length; ++i)    {        array_insert_prev(array, i, &a[i]);    }    for(i = 0; i < length; ++i)    {        array_insert_next(array, i, &a[i]);    }    printf("array_count:");    printf("%d \n",get_array_count(array));    length = get_array_count(array);    printf("length:%d\n",length);    printf("Array :\n");    for(i = 0; i < length; ++i)    {        printf("%d ",*(int *)array->data[i]);    }    printf("\n");    printf("array_index_count_2:");    printf("%d \n",*(int *)get_index_value(array, 2));    printf("delete_index_value(array, 2):\n");    delete_index_value(array, 2);    length = get_array_count(array);    for(i = 0; i < length; ++i)    {        printf("%d ",*(int *)array->data[i]);    }    printf("\n");    delete_range_value(array, 1, 3);    length = get_array_count(array);    for(i = 0; i < length; ++i)    {        printf("%d ",*(int *)array->data[i]);    }    printf("\n");/*    foreach(iter, array)    {        printf("%d ",*(int *)array->data[i]);   } */    printf("find_array_value(array, ?)\n");    printf("array[5]: %d \n",find_array_value(array, &array->data[5]));    printf("array[3]:%d \n",find_array_value(array, &array->data[3]));    printf("\n");    printf("clean_array(array)\n");    clean_array(array);    length = get_array_count(array);    for(i = 0; i < length; ++i)    return 0;}

运行结果:

root@aemonair:# cc.sh *.c Compiling ...-e CC      dynamic_array.c main.c tools.c -g -lpthread-e         Completed .-e         Fri Jun 24 11:51:10 CST 2016root@aemonair:~# ./dynamic_array array_count:10 length:10Array :1 2 3 4 5 1 2 3 4 5 array_index_count_2:3 delete_index_value(array, 2):1 2 4 5 1 2 3 4 5 1 1 2 3 4 5 find_array_value(array, ?)array_count:6array[5]: 5 array_count:6array[3]:3 clean_array(array)

总结

至此,我们已经完成了动态数组的实现。
我们可以从中看到,C语言可以用来实现各种各样的数据结构,同时,作为动态数组,我们多次使用malloc和free等函数,需要对内存的申请释放特别注意。
我们在其中所使用的各种通用思想,以及迭代器的方法,需要再深入理解。通过我们的新鲜知识对旧的知识点进行进一步拓展和提升。

0 0