自学数据结构系列-实现数组

前言

数据结构就是将大量而复杂的数据类型和特定的存储结构保存到主存储器,并在此基础上为了实现某个功能而执行的相应操作。 -- by 郝斌视频

今天研究并实现了数据结构中线性结构之一的数组实现。

数组就是一组连续存储的数据。

要实现的功能:

  1. 拼接 append
  2. 添加 insert
  3. 删除 delete
  4. 排序 sort
  5. 获取数组长度 len
  6. 判断数组是否为空 isempty
  7. 判断数组是否已满 isfull
  8. 打印显示数组数据 show
// 1. 创建数组
void init_arr(PARRAYLIST pArray, int len);
// 2. 获取数组长度
int  len_arr(PARRAYLIST pArray);
// 3. 判断数组是否为空
bool isempty_arr(PARRAYLIST pArray);
// 4. 判断数组是否已满
bool isfull_arr(PARRAYLIST pArray);
// 5. 拼接数据
bool append_arr(PARRAYLIST pArray, int val);
// 6. 插入数据
bool insert_arr(PARRAYLIST pArray, int pos, int val);
// 7. 删除数据
bool delete_arr(PARRAYLIST pArray, int pos, int * pVal);
// 8. 数组排序
void sort_arr(PARRAYLIST pArray);
// 9. 打印显示
void show_arr(PARRAYLIST pArray);

首先我们要创建一个数组,那么数组在代码中怎么体现的呢?面向对象语言中,数组就是一个对象,C 语言是面向过程语言,并不存在对象一说,因此可以考虑使用结构。

数组的结构,数组我们需要了解哪些东西

  1. 肯定是数据,而且是保存一长串数据就会用到数组,我们这里使用指针保存数据;
  2. 既然是一个不可变数组,需要给数组指定一个总长度;
  3. 然后在指定一个有效长度,来保存数组中真实存储的数据个数。
// 数据结构:数组实现
typedef struct ArrayList {
    int * pbase;    // 保存数据的第一个指针
    int len;        // 数组长度
    int cnt;        // 数组有效长度
}ARRAYLIST, *PARRAYLIST;

OK,现在有数组了,我们要操作一个对象是不是需要有这个对象呐,现在要创建一个数组,C 语言中结构体并不会像面向对象语言中的对象可以跨函数调用。

C 语言中跨函数调用必须是动态分配内存,因此我们这个数组就需要我们动态分配内存。

接下来使用 malloc 函数,也就是 C 语言中动态分配内存的方法,创建数组并为其分配内存。

/**
 创建数组

 @param pArray 操作数组
 @param len 创建数组长度
 */
void init_arr(PARRAYLIST pArray, int len)
{
    // 1. 为指针域分配空间
    pArray->pbase = (int *)malloc(sizeof(int)*len);
    
    if (NULL == pArray->pbase) {
        printf("内存分配失败!\n");
        exit(-1);
    }
    
    // 初始化数组其他参数
    pArray->len = len;
    pArray->cnt = 0;
    
    return;
}

现在有了数组,我们就应该实现数组的方法了。

首先,我们先实现获取长度的方法,也很简单,在结构体 ArrayList 中我们保存了一个 cnt 字段来表示有效长度,所有我们数组的长度就是这个 cnt 字段的值。

/**
 获取数组长度

 @param pArray 操作数组
 @return 数组长度
 */
int  len_arr(PARRAYLIST pArray)
{
    return pArray->cnt;
}

然后,判断数组是否为空, 那么数组什么时候为空呢?当然是数组中没有数据,也就是数组有效长度为 0 的时候。

/**
 判断数组是否为空

 @param pArray 操作数组
 @return 是否为空
 */
bool isempty_arr(PARRAYLIST pArray)
{
    return pArray->cnt == 0;
}

接下来,判断数组是否已满,那么数组什么时候已满呢?当然是当数组中的个数等于数组总长度的时候。

/**
 判断数组是否已满

 @param pArray 操作数组
 @return 数组是否已满
 */
bool isfull_arr(PARRAYLIST pArray)
{
    return pArray->cnt == pArray->len;
}

再然后,我们来实现拼接、插入和删除的逻辑。

拼接就是在数组最后插入一条数据,那么只要知道当前数组的个数 count,并将拼接数据插入到 count+1 的位置,当然不要忘记把我们有效数据的表示为 +1。

/**
 拼接数据

 @param pArray 操作数组
 @param val    拼接数据
 @return 拼接是否成功
 */
bool append_arr(PARRAYLIST pArray, int val)
{
    if (isfull_arr(pArray)) {
        printf("数组已满, 拼接操作失败\n");
        return false;
    }
    
    pArray->pbase[pArray->cnt] = val;
    pArray->cnt ++;
    
    return true;
}

插入操作需要接受三个参数,一个是数组地址,一个
插入位置,最后是数值。

其实拼接操作可以看做插入操作的一个特例,因为我们可以自己计算出了,省略了插入位置,由拼接操作可以推算出插入操作执行步骤。

第一步,需要定位到要插入的位置。

第二步,插数据到这个位置。

咦,貌似不对,数据是插进去,位置也对,但是数组的长度怎么没有变,好像少了一个数吧。

每次,我们是插入数据,但是我们把原来位置数据替换成了我们要插的数据,但是原来数据却丢了!因此,我们需要在插数据前在执行一个步骤。

将当前位置数据以及其后所有数据都往后移动一个位置,当然不要忘记把我们有效数据的表示为 +1。

/**
 插入数据

 @param pArray 操作数组
 @param pos 插入位置
 @param val 插入值
 @return 插入是否成功
 */
bool insert_arr(PARRAYLIST pArray, int pos, int val)
{
    if (isfull_arr(pArray)) {
        printf("数组已满, 拼接操作失败\n");
        return false;
    }
    if (0 > pos - 1 || pos > pArray->cnt + 1) {
        printf("插入位置不合法!\n");
        return false;
    }
    
    if (pos == pArray->cnt + 1) {
        
        pArray->pbase[pos - 1] = val;
        pArray->cnt ++;
        
        return true;
    }
    
    int i ;
    
    for (i = pArray->cnt; i >= pos - 1; -- i) {
        pArray->pbase[i] = pArray->pbase[i - 1];
    }
    
    pArray->pbase[pos - 1] = val;
    pArray->cnt ++;
    
    return true;
}

删除操作跟插入操作是反向操作。

既然插入操作要将插入位置以及之后的数据后移一位,那么作为死对头,删除肯定就是将删除位置之后的数据前移一位,然后修改有效数据的标识 -1。

/**
 删除数据

 @param pArray 操作数组
 @param pos 删除位置
 @param pVal 删除值
 @return 是否删除成功
 */
bool delete_arr(PARRAYLIST pArray, int pos, int * pVal)
{
    if (isempty_arr(pArray)) {
        printf("数组为空,不能执行删除操作!\n");
        exit(-1);
    }
    if (0 > pos - 1 || pos > pArray->cnt) {
        printf("删除位置不合法!\n");
        return false;
    }
    
    *pVal = pArray->pbase[pos - 1];
    
    if (pos == pArray->cnt + 1) {
        
        pArray->cnt --;
        
        return true;
    }
    
    int i ;
    
    for (i = pos - 1; i < pArray->cnt; ++ i) {
        pArray->pbase[i] = pArray->pbase[i + 1];
    }
    
    pArray->cnt --;
    
    return true;
    
}

最后就是数组排序和显示了,对于接触过面向对象语言的各位,排序应该是常客了,较为常见的排序有顺序和冒泡两种,在这里就不啰嗦了,直接上代码

/**
 数组排序

 @param pArray 操作数组
 */
void sort_arr(PARRAYLIST pArray)
{
    int i, j, t;
    
    for (i = 0; i < pArray->cnt - 1; ++ i) {
        for (j = i; j < pArray->cnt; ++ j) {
            
            if (pArray->pbase[i] > pArray->pbase[j]) {
                t = pArray->pbase[j];
                pArray->pbase[j] = pArray->pbase[i];
                pArray->pbase[i] = t;
            }
            
        }
    }
}
/**
 打印显示

 @param pArray 操作数组
 */
void show_arr(PARRAYLIST pArray)
{
    int i ;
    
    for (i = 0; i < pArray->cnt; ++ i) {
        printf("%d ", pArray->pbase[i]);
    }
    printf("\n");
    
    return;
}

到目前为止,C 语言实现数组的任务基本完工,剩下的就是测试和拓展新功能了。

如果各位客官有兴趣可以在此基础上完善,或者有什么需求也可以提出,如果我能完成也可以分享出来。

各路大牛轻喷,新手练手,有错请指出。

下面放出完整代码供大家学习,喜欢请 star 谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容