C語言實現數組的動態分配
作者:白寧超
2016年10月27日20:13:13
摘要:數據結構和算法對於編程的意義不言而喻,具有指導意義的。無論從事算法優化方向研究,還是大數據處理,亦或者網站開發APP開發雲雲。在求職過程中數據結構必然也是筆試的重點,面試的常客。基於此,系統梳理復習下數據結構和算法相關知識,其實核心為鏈表操作,串的匹配,樹的先序、中序、后序。排序的相關操作,查找相關操作,深度優先遍歷、廣度優先遍歷、哈弗曼樹、動態規划等。本節為開胃菜,數組的相關操作(本文原創編著,轉載注明出處:C語言實現數組的動態分配)
1 數組動態分配思想
數組是最常用的數據結構,在內存中連續存儲,可以靜態初始化(int a[2]={1,2}),可以動態初始化 malloc()。難點就是數組在刪除或者插入元素的時候,要移動元素的坐標不好確定。規律:
1.如果要在數組中第pos個位置插入一個元素(應該從后面開始移動)
for( i=cnu;i>=pos;i--) pBase[i]=pBase[i-1];
2.刪除數組第pos位置的元素
for(i=pos+1;i<=cnu;i--) pBase[i-2]=pBase[i-1];
使用malloc動態分配內存並將返回值賦給整形指針
int pBase=(int *)malloc(sizeof(int)len);//分配4*len字節長度的內存
這是pBase可以指向數組中的第一個元素,可以作為數組變量名稱使用。
2 數組的優缺點
優點:
存取速度快 o(1) 可以直接根據下標找到內存位置
缺點:
- 事先必須知道數組的長度
- 插入刪除元素很慢
- 空間通常是有限制的
- 需要大塊連續的內存塊
- 插入刪除元素的效率很低
3 完整案例
#include<stdio.h> #include<malloc.h> #include<stdbool.h> /* 定義結構體 */ struct Arr{ int len;//數組能存取的最大元素個數 int cnu;//數組中當前元素個數 int *pBase;//存儲指向數組的指針 }; /*初始化數組*/ void init_Arr(struct Arr *pArray,int len){ pArray->pBase=(int*)malloc(sizeof(int)*len);//分配4*len字節長度的內存 if(NULL== pArray->pBase){ printf("動態分配內存失敗\n"); }else{ pArray->len=len; pArray->cnu=0; printf("動態分配內存成功 %d \n",pArray->len); } } /*判斷數組是否為空,傳地址省內存4字節,傳結構體變量需要進行拷貝,12字節*/ bool isempty(struct Arr *pArray){ if(0==pArray->cnu) return true; else return false; } /*判斷數組是否滿了*/ bool isfull(struct Arr *pArray){ if(pArray->len==pArray->cnu) return true; else return false; } /*顯示數組內容*/ void show_Arr(struct Arr *pArray){ if(isempty(pArray)) printf("數組為空!\n"); else{ for(int i=0; i<pArray->cnu;i++){ printf("%d \t\t %d \t\t %d \n",pArray->pBase[i],pArray->cnu,pArray->len); } printf("------------------------------------\n"); } } /*向數組追加元素*/ bool append(struct Arr *pArray,int val){ if(isfull(pArray)){ printf("數組已經滿了!\n"); return false; }else{ pArray->pBase[pArray->cnu]=val; pArray->cnu++; } } /*向數組中插入元素,pos為數組中第幾個位置,pos=3就是向a[2]插入元素*/ bool insert(struct Arr *pArray,int pos,int val){ if(pos<1||pos>pArray->len+1){ printf("插入的位置輸入的不合法\n"); return false; } if(isfull(pArray)){ printf("數組已經滿了,插入失敗!\n"); return false; } else{ //printf("數組 %d \n",pArray->cnu); for(int i=pArray->cnu;i>=pos;i--){//循環將pos位置開始的數組后移 pArray->pBase[i]=pArray->pBase[i-1]; } pArray->pBase[pos-1]=val; pArray->cnu++; pArray->len++; return true; } } /*刪除數組中的第pos個元素,同時返回刪除的元素的值*/ bool delete(struct Arr *pArray,int pos,int *val){ if(pos<1||pos>pArray->cnu){ printf("刪除失敗,位置不合法\n"); return false; } if(isempty(pArray)){ printf("數組已經空,刪除失敗!\n"); return false; } else{ *val=pArray->pBase[pos-1]; for(int i=pos+1;i<=pArray->cnu;i++){ pArray->pBase[i-2]=pArray->pBase[i-1]; } pArray->cnu--; return true; } } /*數組倒置*/ bool inverse(struct Arr *pArray){ if(isempty(pArray)){ printf("倒置失敗,因數組為空"); return false; } else{ int i=0,j=pArray->cnu-1,temp; while(i<j){ temp=pArray->pBase[i]; pArray->pBase[i]=pArray->pBase[j]; pArray->pBase[j]=temp; i++; j--; } } return true; } int main(){ struct Arr arr; init_Arr(&arr,20); append(&arr,1); append(&arr,2); append(&arr,3); append(&arr,4); append(&arr,5); show_Arr(&arr); insert(&arr,2,88); show_Arr(&arr); int val; delete(&arr,1,&val); show_Arr(&arr); printf("刪除了 %d\n",val); inverse(&arr); show_Arr(&arr); return 0; }
4 運行結果
Success time: 0 memory: 2300 signal:0
動態分配內存成功 20 1 5 20 2 5 20 3 5 20 4 5 20 5 5 20 ------------------------------------ 1 6 21 88 6 21 2 6 21 3 6 21 4 6 21 5 6 21 ------------------------------------ 88 5 21 2 5 21 3 5 21 4 5 21 5 5 21 ------------------------------------ 刪除了 1 5 5 21 4 5 21 3 5 21 2 5 21 88 5 21 ------------------------------------
5 實例解析
結構體:結構體(struct)指的是一種數據結構,是C語言中聚合數據類型的一類。 結構體可以被聲明為變量、指針或數組等,用以實現較復雜的數據結構。結構體的定義如下所示,
struct tag { member-list } variable-list ;
struct為結構體關鍵字,tag為結構體的標志,member-list為結構體成員列表,其必須列出其所有成員;variable-list為此結構體聲明的變量。
思路:
- 創建結構體記得關鍵字struct
- 花括號內創建結構體屬性
例如:
/* 定義結構體 */ struct Arr{ int len;//數組能存取的最大元素個數 int cnu;//數組中當前元素個數 int *pBase;//存儲指向數組的指針 };
初始化數組:
思路:
- 創建初始化函數,給數組分配長度malloc(sizeof(int)*len
- 指針地址為空,分配內存失敗
- 反之,數組長度為當前內存長度,數組當前位置為0
例如:
/*初始化數組*/ void init_Arr(struct Arr *pArray,int len){ pArray->pBase=(int*)malloc(sizeof(int)*len);//分配4*len字節長度的內存 if(NULL== pArray->pBase){ printf("動態分配內存失敗\n"); }else{ pArray->len=len; pArray->cnu=0; printf("動態分配內存成功 %d \n",pArray->len); } }
判斷數組是否為空:
- 創建判空函數,結構體參數數組
- 判斷當前元素個數是否為空
/*判斷數組是否為空,傳地址省內存4字節,傳結構體變量需要進行拷貝,12字節*/ bool isempty(struct Arr *pArray){ if(0==pArray->cnu) return true; else return false; }
判斷數組是否為滿:
- 創建判滿函數,結構體參數數組
- 判斷數組長度是否為當前元素長度
例如:
/*判斷數組是否滿了*/ bool isfull(struct Arr *pArray){ if(pArray->len==pArray->cnu) return true; else return false; }
向數組追加元素:
- 創建追加函數,結構體數組參數,元素值
- 注意判滿情況,反之循環輸入
- 數組當前指針地址賦值
- 數組指向下一個位置,自加
例如:
/*向數組追加元素*/ bool append(struct Arr *pArray,int val){ if(isfull(pArray)){ printf("數組已經滿了!\n"); return false; }else{ pArray->pBase[pArray->cnu]=val; pArray->cnu++; } }
顯示數組內容
- 創建顯示函數,結構體數組參數
- 注意判空情況,反之循環輸入
- 遍歷數組輸出
例如:
/*顯示數組內容*/ void show_Arr(struct Arr *pArray){ if(isempty(pArray)) printf("數組為空!\n"); else{ for(int i=0; i<pArray->cnu;i++){ printf("%d \t\t %d \t\t %d \n",pArray->pBase[i],pArray->cnu,pArray->len); } printf("------------------------------------\n"); } }
向數組中插入元素:pos為數組中第幾個位置,pos=3就是向a[2]插入元素
- 創建插入函數,結構體數組參數,位置參數,插入值參數
- 判斷插入位置是否越界,判斷數組是否滿
- 循環將pos位置開始的數組后移,移動范圍是從第pos個到第cnu個
- 循環將pos位置開始的數組后移,將值插入pos處
- 指向下一位且長度加1
例如:
/*向數組中插入元素,pos為數組中第幾個位置,pos=3就是向a[2]插入元素*/ bool insert(struct Arr *pArray,int pos,int val){ if(pos<1||pos>pArray->len+1){ printf("插入的位置輸入的不合法\n"); return false; } if(isfull(pArray)){ printf("數組已經滿了,插入失敗!\n"); return false; } else{ //printf("數組 %d \n",pArray->cnu); for(int i=pArray->cnu;i>=pos;i--){//循環將pos位置開始的數組后移 pArray->pBase[i]=pArray->pBase[i-1]; } pArray->pBase[pos-1]=val; pArray->cnu++; pArray->len++; return true; } }
刪除數組中的第pos個元素:同時返回刪除的元素的值
- 創建插入函數,結構體數組參數,位置參數,插入值參數
- 判斷插入位置是否越界合法
- 獲取刪除的元素值
- 移動單位是從第pos+1個到cnu
- 指針向前指向,自減
例如:
/*刪除數組中的第pos個元素,同時返回刪除的元素的值*/ bool delete(struct Arr *pArray,int pos,int *val){ if(pos<1||pos>pArray->cnu){ printf("刪除失敗,位置不合法\n"); return false; } if(isempty(pArray)){ printf("數組已經空,刪除失敗!\n"); return false; } else{ *val=pArray->pBase[pos-1]; for(int i=pos+1;i<=pArray->cnu;i++){ pArray->pBase[i-2]=pArray->pBase[i-1]; } pArray->cnu--; return true; } }
數組倒置
- 創建倒置函數,判斷數組是否為空
- 三個變量進行交換,其中temp中間變量,ij分別指向數組首尾索引
- 循環數組,使前后索引交換位置
- 每一遍循環,ij索引分別前進一步,直到跳出循環,程序結束
例如:
/*數組倒置*/ bool inverse(struct Arr *pArray){ if(isempty(pArray)){ printf("倒置失敗,因數組為空"); return false; } else{ int i=0,j=pArray->cnu-1,temp; while(i<j){ temp=pArray->pBase[i]; pArray->pBase[i]=pArray->pBase[j]; pArray->pBase[j]=temp; i++; j--; } } return true; }