1. 程式人生 > >【演算法】C語言實現陣列的動態分配

【演算法】C語言實現陣列的動態分配

作者:白寧超

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) 可以直接根據下標找到記憶體位置

缺點:

  1. 事先必須知道陣列的長度
  2. 插入刪除元素很慢
  3. 空間通常是有限制的
  4. 需要大塊連續的記憶體塊
  5. 插入刪除元素的效率很低

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為此結構體宣告的變數。

思路:

  1. 建立結構體記得關鍵字struct
  2. 花括號內建立結構體屬性

例如:

/* 定義結構體 */
struct Arr{
	int len;//陣列能存取的最大元素個數
	int cnu;//陣列中當前元素個數
	int *pBase;//儲存指向陣列的指標
};

初始化陣列:

思路:

  1. 建立初始化函式,給陣列分配長度malloc(sizeof(int)*len
  2. 指標地址為空,分配記憶體失敗
  3. 反之,陣列長度為當前記憶體長度,陣列當前位置為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);
	}
} 

判斷陣列是否為空:

  1. 建立判空函式,結構體引數陣列
  2. 判斷當前元素個數是否為空 
/*判斷陣列是否為空,傳地址省記憶體4位元組,傳結構體變數需要進行拷貝,12位元組*/
bool isempty(struct Arr *pArray){
	if(0==pArray->cnu) return true;
	else return false;
}

判斷陣列是否為滿:

  1. 建立判滿函式,結構體引數陣列
  2. 判斷陣列長度是否為當前元素長度 

例如:

/*判斷陣列是否滿了*/
bool isfull(struct Arr *pArray){
  if(pArray->len==pArray->cnu)	return true;
  else return false;
}

向陣列追加元素:

  1. 建立追加函式,結構體陣列引數,元素值
  2. 注意判滿情況,反之迴圈輸入
  3. 陣列當前指標地址賦值
  4. 陣列指向下一個位置,自加

例如:

/*向陣列追加元素*/
bool append(struct Arr *pArray,int val){
	if(isfull(pArray)){
		printf("陣列已經滿了!\n");
		return false;
	}else{
		pArray->pBase[pArray->cnu]=val;
		pArray->cnu++;
	}
}

顯示陣列內容 

  1. 建立顯示函式,結構體陣列引數
  2. 注意判空情況,反之迴圈輸入
  3. 遍歷陣列輸出

例如:

/*顯示陣列內容*/
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]插入元素

  1. 建立插入函式,結構體陣列引數,位置引數,插入值引數
  2. 判斷插入位置是否越界,判斷陣列是否滿
  3. 迴圈將pos位置開始的陣列後移,移動範圍是從第pos個到第cnu個
  4. 迴圈將pos位置開始的陣列後移,將值插入pos處
  5. 指向下一位且長度加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個元素:同時返回刪除的元素的值

  1. 建立插入函式,結構體陣列引數,位置引數,插入值引數
  2. 判斷插入位置是否越界合法
  3. 獲取刪除的元素值
  4. 移動單位是從第pos+1個到cnu
  5. 指標向前指向,自減

例如:

/*刪除陣列中的第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;
	}
}

陣列倒置

  1. 建立倒置函式,判斷陣列是否為空
  2. 三個變數進行交換,其中temp中間變數,ij分別指向陣列首尾索引
  3. 迴圈陣列,使前後索引交換位置
  4. 每一遍迴圈,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;
}