線性表:順序表(靜態分配、動態分配)

順序表:線性表的順序存儲實現。

靜態分配方式

靜態分配一個數組,由於沒有使用動態分配內存的方式(malloc),所以並沒有DestroyList(&L)函數,在程序結束後會自動銷燬該數組。重要的操作有:

  • InitList(&L) :初始化順序表。
  • ListInsert(&L,i,e):在L的位序i處插入元素e。
  • ListDelete(&L,i,&e):刪除L位序i處的元素,並賦給e。
  • GetElem(L,i):按位查找,返回元素值。
  • LocateElem(L,e):按值查找,找到第一個與e相等的元素,並返回其位序。
// 線性表(linear list)的順序存儲方式--順序表
// 順序表的靜態分配方式
//ElemType:int 
#include<stdio.h>
#define MaxSize 10 //定義順序表最大長度 
typedef struct{
	int data[MaxSize];//靜態數組存放數據元素 
	int length;//順序表的當前長度 
}SqList;

void InitList(SqList &L){//初始化一個順序表 
	for(int i=0;i<MaxSize;i++){
		L.data[i]=0;
	}
	L.length=5;
}

//not important functions
void PrintList(SqList L){//打印輸出順序表 
	for(int i=0;i<L.length;i++)
		printf("data[%d]=%d\n",i,L.data[i]);
}
int Length(SqList L){//求表長 
	return L.length;
}
bool Empty(SqList L){//判空操作 
	if(L.length==0){
		return true;
	}else{
		return false;
	}
}

//important functions
bool ListInsert(SqList &L,int i,int e){//在L的位序i處插入元素e 
	if(i<1||i>L.length+1){//判斷i的範圍是否有效 
		return false;
	}
	if(L.length>=MaxSize){//存儲空間已滿,不能插入 
		return false;
	}
	for(int j=L.length;j>i-1;j--){//將第i個元素及以後的元素後移 
		L.data[j]=L.data[j-1];
	}
	L.data[i-1]=e;
	L.length++;
	return true;
}
bool ListDelete(SqList &L,int i,int &e){//刪除L的位序爲i的元素,將被刪除的元素賦給e 
	if(i<1||i>L.length){
		return false;
	}
	e=L.data[i-1];//將被刪除的元素賦給e
	for(int j=i-1;j<L.length-1;j++){
		L.data[j]=L.data[j+1];
	}
	L.length--;
	return true;
}
int GetElem(SqList L,int i){//按位查找,獲取L中第i個位置的元素值 
	/*這裏可以檢查參數是否合法*/
	if(i<1||i>L.length){
		printf("查找位序不合法!");
		return -1;
	}
	return L.data[i-1];
}
int LocateElem(SqList L,int e){//按值查找,找到L中第一個等於e的元素,並返回其位序 
	for(int i=0;i<L.length;i++){
		if(L.data[i]==e){
			return i+1;
		}
	}
	return 0;
}

int main(){
	SqList L;
	InitList(L);
	ListInsert(L,3,3);
	PrintList(L);
	int e = -1;
	if(ListDelete(L,3,e)){
		printf("已經刪除第3個元素,刪除元素爲%d\n",e);
	}else{
		printf("位序i不合法,刪除失敗\n");
	}
	return 0;
}

動態分配

動態分配的方式數據元素在內存中依然是連續的,順序的,只不過是長度是動態的。重要的操作有:

  • InitList(&L) :初始化順序表。
  • IncreaseSize(&L):延長順序表。
  • ListInsert(&L,i,e):在L的位序i處插入元素e。
  • ListDelete(&L,i,&e):刪除L位序i處的元素,並賦給e。
  • GetElem(L,i):按位查找,返回元素值。
  • LocateElem(L,e):按值查找,找到第一個與e相等的元素,並返回其位序。

延長順序表可以用malloc重新開闢一塊內存,將數據複製過去,也可使用realloc嘗試重新調整之前調用malloc所分配的內存塊的大小:void *realloc(void *ptr, size_t size);但是可能realloc有時候會出問題?我猜是在原來內存塊上延長可能會“撞”到其他的已用的內存塊,導致發生錯誤。所以用malloc較爲保險。

(int*)realloc(L.data,L.MaxSize+len);

同時要注意動態分配方式是有銷燬順序表的操作的,另外,函數中的指針free(p)釋放p所指向的內存,沒有寫p=NULL,因爲是在函數裏的,函數結束後會回收;而在銷燬方法裏的銷燬數據結構時,在free(L.data)後是要L.data=NULL置空的,手動銷燬。

// 線性表(linear list)的順序存儲方式--順序表
// 順序表的靜態分配方式
//ElemType:int 
#include<stdio.h>
#include<stdlib.h>
#define InitSize 10 //表長度的初始定義
typedef struct{
	int* data;//指示動態分配數組的指針 
	int MaxSize,length;//數組的最大容量和當前長度 
}SeqList;

void InitList(SeqList &L){
	L.data=(int*)malloc(InitSize*sizeof(int));
	L.length=0;
	L.MaxSize=InitSize;
}
void IncreaseSize(SeqList &L,int len){//增加動態數組長度len
    //(int*)realloc(L.data,L.MaxSize+len); 
	int* p=L.data;
	L.data=(int*)malloc((L.MaxSize+len)*sizeof(int));
	for(int i=0;i<L.length;i++){
		L.data[i]=p[i];//將數據複製到新區域 
	}
	L.MaxSize=L.MaxSize+len;
	free(p);//釋放p所指向的內存區域,函數結束後p會被系統回收。 
}

//not important functions
void PrintList(SeqList L){
	for(int i=0;i<L.length;i++){
		printf("data[%d]=%d\n",i,L.data[i]);
	}
}
int Length(SeqList L){
	return L.length;
}
bool Empty(SeqList L){
	if(L.length==0){
		return true;
	}else{
		return false;
	}
}
bool DestroyList(SeqList &L){//銷燬順序表 
	if(L.data){
		free(L.data);//釋放L.data指向的內存區域
		L.data=NULL;//釋放L.data指針本身
		L.length=0;
		L.MaxSize=0; 
	}else{
		return false;
	}
	return true;
}

//important functions
bool ListInsert(SeqList &L,int i,int e){//將e插入到L的位序i處 
	if(i<1||i>L.length+1){
		return false;
	}
	if(L.length>=L.MaxSize){
		return false;
	}
	for(int j=L.length;j>i-1;j--){
		L.data[j]=L.data[j-1];
	}
	L.data[i-1]=e;
	L.length++;
	return true;
}
bool ListDelete(SeqList &L,int i,int &e){//刪除位序爲i的元素,並將刪除的元素賦給e 
	if(i<1||i>L.length){
		return false;
	}
	e=L.data[i-1];
	for(int j=i-1;j<L.length-1;j++){
		L.data[j]=L.data[j+1];
	}
	L.length--;
	return true;
}
int GetElem(SeqList L,int i){//按位查找,獲取位序爲i的元素 
	if(i<1||i>L.length){
		printf("查找位序不合法!"); 
		return -1;
	}
	return L.data[i-1];
}
int LocateElem(SeqList L,int e){//按值查找,找到L中第一個等於e的元素,並返回其位序 
	for(int i=0;i<L.length;i++){
		if(L.data[i]==e){
			return i+1;
		}
	}
	return 0;
}

int main(){
	SeqList L;
	InitList(L);
	ListInsert(L,3,3);
	PrintList(L);
	int e = -1;
	if(ListDelete(L,3,e)){
		printf("已經刪除第3個元素,刪除元素爲%d\n",e);
	}else{
		printf("位序i不合法,刪除失敗\n");
	}
	IncreaseSize(L,3);
	printf("len:%d\n",L.MaxSize);
	DestroyList(L);
	return 0;
}

小結

順序表的靜態分配與動態分配只不過是一個數組長度固定,一個數組長度可以動態變化的。在物理存儲上都是連續的、順序的。

動態分配方式指針L.data同樣可以用數組下標取數,所以在進行一系列操作時並沒有什麼區別。無非需要注意的是:

【靜態分配】外部define:MaxSize,結構體內:L.length。

【動態分配】外部define:InitSize,結構體內:L.length,L.MaxSize。另外動態分配會有延長數組的操作和銷燬操作。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章