【演算法】C語言實現陣列的動態分配
阿新 • • 發佈:2018-12-31
作者:白寧超
2016年10月27日20:13:13
摘要:資料結構和演算法對於程式設計的意義不言而喻,具有指導意義的。無論從事演算法優化方向研究,還是大資料處理,亦或者網站開發APP開發云云。在求職過程中資料結構必然也是筆試的重點,面試的常客。基於此,系統梳理複習下資料結構和演算法相關知識,其實核心為連結串列操作,串的匹配,樹的先序、中序、後序。排序的相關操作,查詢相關操作,深度優先遍歷、廣度優先遍歷、哈弗曼樹、動態規劃等。本節為開胃菜,陣列的相關操作
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; }