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;
}
