資料結構之順序表的實作
一、原理
1.定義
順序表是在計算機中以陣列形式保存的,
2.特點
-
在計算機中占用連續的一段記憶體
-
一旦宣告,空間大小一般不變
二、初始化相關操作
包括:
- 結構體的定義
- 順序表的創建
- 順序表清空
- 判斷順序表是否為空
1.結構體定義
即定一個滿足順序表定義的結構體,其中包含 陣列、存盤長度、總長度,
typedef int ElemType; //將int抽象為ElemType,表明順序表也可以存盤其他型別(如將int改為char)
struct List
{
ElemType *list;
//宣告陣列用于給順序表存盤資料,等價于以下宣告方式
//ElemType[] list;
int length; //用于記錄順序表存盤的資料長度
int MaxSize; //用于記錄順序表最大長度(即最多存盤資料)
}
2.初始化
對順序表進行初始化,包括分配自定義長度的陣列空間,設定存盤長度為0,存盤長度為規定值
//初始化,傳入需要初始化的順序表和初始化長度
void InitList(struct List *L,int maxSize){
//初始化長度合法性判斷
if(maxSize<0){
printf("初始化長度非法!\n");
exit(1); //退出程式
}
//對順序表長度進行賦值
L->MaxSize = maxSize;
//根據初始化長度和存盤資料型別來動態分配陣列
L->list = malloc(sizeof(maxSize*sizeof(ElemType)));
//分配成功判定
if(!L->list){
printf("動態分配存盤失敗\n");
exit(1);
}
//初始化存盤資料為0個
L->length = 0;
}
3.清空
將順序表內容清空,用于某些題目要求或節省空間
//清空,傳入需要清空的順序表
void ClearList(struct List *L){
//判斷順序表是否已經為空
if(L->list!=NULL){
free(L->list); //釋放順序表中陣列記憶體
L->list = 0;
L->length = 0;
L->MaxSize = 0;
}
}
4. 判斷是否為空
判斷順序表是否為空,在某些操作之前,先要判斷順序表是否為空,防止出錯
int isEmpty(struct List *L){
return L->length==0?1:0; //順序表最大長度為0則為慷訓傳1,否則回傳0
}
三、增加相關操作
包括:
- 向表頭插入元素x
- 向表尾插入元素x
- 向第n個位置插入元素x
- 向遞增的線性表中插入元素x,之后仍然保持有序
進行操作之前,還需要一個方法,當插入元素超過陣列長度時,將陣列容量擴大,即重新申請空間
Tip:將順序表擴大一倍空間
void ReMalloc(struct List *L){
ElemType *p = realloc(L->list,2*L->MaxSize*sizeof(ElemType));
if(!p){
printf("空間分配失敗\n");
exit(1);
}
L->list = p; //使list重新指向新生成的空間
L->MaxSize = 2*L->MaxSize;
printf("存盤空間已經擴大為2倍\n");
}
1.向表頭插入元素x
void insertElemToHead(struct List *L,ElemType x){
int i;
//判斷存盤空間是否已滿
if(L->length==L->MaxSize){
printf("存盤空間已滿,重新分配中...");
ReMalloc(L);
}
//所有元素后移
for(i=L->length;i>0;i--){
L->list[i+1]=L->list[i];
}
L->list[i]=x;
L->length++;
}
2.向表尾插入元素x
void insertElemToTail(struct List *L,ElemType x){
//判斷存盤空間是否已滿
if(L->length==L->MaxSize){
printf("存盤空間已滿,重新分配中...");
ReMalloc(L);
}
L->list[L->length++]=x;
}
3.向線性表L的第n個位置插入元素x
void insertElemSomewhere(struct List *L,ElemType x,int n){
//判斷存盤空間是否已滿
if(L->length==L->MaxSize){
printf("存盤空間已滿,重新分配中...");
ReMalloc(L);
}
int i;
for(i=L->length;i>=n;i--){
L->list[i] = L->list[i-1];
}
L->list[i] = x;
L->length--;
}
四、洗掉相關操作
包括:
-
洗掉表頭元素并回傳被洗掉的值
-
洗掉第n個元素并回傳被洗掉元素
-
從線性表L中洗掉值為X的第一個元素
1.洗掉表頭元素并回傳被洗掉的值
洗掉表頭第一個元素,長度減少1,回傳被洗掉的值
ElemType delHeadElem(struct List *L){
ElemType x = L->list[0];
//合法性判斷
if(L->length==0){
printf("線性表為空,不能洗掉\n");
exit(1);
}
for(int i=0;i<L->length;i++){
L->list[i] = L->list[i+1];
}
L->length--;
return x;
}
2.洗掉第n個元素并回傳被洗掉元素
ElemType delSomeElem(struct List *L,int n){
if(n<L->length){
printf("n位置越界,不能洗掉");
exit(1);
}
ElemType x = L->list[n-1];
for(int i=n;i<L->length;i++){
L->list[i]=L->list[i+1];
}
L->length--;
retur x;
}
3.從線性表L中洗掉值為X的第一個元素
從線性表L中洗掉值為X的第一個元素,若洗掉成功則回傳1,否則回傳0
int delElemKnown(struct List *L,ElemType x){
int i,j;
//先找出值為X的下標
for(i=0;i<L->length;i++){
if(L->list[i]==x){
break;
}
}
for(j=i;i<L->length;j++){
L->list[j]=L->list[j+1];
}
L->length--;
return 1;
}
五、修改相關操作
包括:
- 把線性表中第n個元素修改為x
1.把線性表中第n個元素修改為x
把線性表中第n個元素修改為x,若成功則回傳1,失敗回傳0
int updateElemKnown(struct List *L,ElemType x,int n){
if(n>L->length||n<1){
return 0;
}
L->list[n]=x;
return 1;
}
六、查找相關操作
包括:
-
查找第n個位置的值
-
順序遍歷輸出所有值
-
回傳值等于x的下標
1.查找第n個位置的值
輸入要查找的坐標,若合法則范圍對應的值,若非法則提示并推出
int getElem(struct List *L,int n){
if(n<0||n>L->MaxSize){
printf("查找位置超出長度!\n");
exit(1);
}
return L->list[n-1]; //n-1的原因是查找的第n個是從1開始計數,而陣列是從0開始計數
}
2.順序遍歷輸出所有值
輸出順序表中的所有值
void getAll(struct List *L){
int i = 0;
while(i<L->length){
printf(L->list[i]+"\t");
i++;
}
printf("\n");
}
3.查找值為x的節點并回傳其坐標
輸入要查找的值x,若存在則范圍首次出現的下標,否則回傳0
void findElem(struct List *L,ElemType x){
int i;
for(i=0;i<L->length;i++){
if(L->list[i]==x){
return i;
}
}
}
七、總結
1.優點
- 查找方便
- 空間利用率高
2.缺點
- 洗掉和增加操作效率低
- 空間固定,不易擴展
八、完整代碼
#include "stdio.h"
#include <stdlib.h>
/**
* =======順序表的定義=========
*/
typedef int ElemType;
//結構體定義
struct List{
ElemType *list;//存盤資料
int length;//存盤長度
int MaxSize;//最大長度
};
//初始化
void initList(struct List *L,int maxSize){
//初始化長度合法性判斷
if(maxSize<0){
printf("初始化長度非法!\n");
exit(1); //退出程式
}
L->MaxSize = maxSize;
L->list = malloc(sizeof(maxSize* sizeof(ElemType)));
//判斷分配空間是否成功
if(!L->list){
printf("空間分配失敗");
exit(1);
}
L->length=0;
}
//清空
void clearList(struct List *L){
if(L->list!=NULL){
free(L->list);
L->list=0;
L->MaxSize=0;
L->length=0;
}
}
//判空
int isEmpty(struct List *L){
return L->length==0?1:0;
}
/**
* =======增加操作=========
*/
//空間再分配
void reMalloc(struct List *L){
ElemType *p = realloc(L->list,2*L->MaxSize* sizeof(ElemType));
if(!p){
printf("空間分配失敗");
exit(1);
}
L->list = p;
L->MaxSize = 2*L->MaxSize;
printf("空間已擴大兩倍");
}
//向表頭插入元素
void insertElemToHead(struct List *L,ElemType x){
if(L->length==L->MaxSize){
reMalloc(L);
printf("空間已滿,重新分配中");
}
for(int i=L->length;i>0;i++){
L->list[i-1] = L->list[i];
}
L->list[0] = x;
L->length++;
}
//向表尾插入元素
void insertElemToTail(struct List *L,ElemType x){
if(L->length==L->MaxSize){
reMalloc(L);
printf("空間已滿,重新分配中");
}
L->list[L->length++] = x;
}
//向線性表L的第n個位置插入元素x
void insertElemSomewhere(struct List *L,ElemType x,int n){
int i;
if(L->length==L->MaxSize){
reMalloc(L);
printf("空間已滿,重新分配中");
}
for(i=L->length;i>=n;i--){
L->list[i]=L->list[i-1];
}
L->list[i]=x;
L->length++;
}
/**
* =======洗掉操作=========
*/
//洗掉表頭元素并回傳被洗掉的值
void delHeadElem(struct List *L){
ElemType x = L->list[0];
if(L->length==0){
printf("順序表為空,洗掉失敗!");
exit(1);
}
for(int i=1;i<L->length;i++){
L->list[i-1] = L->list[i];
}
L->length--;
}
//洗掉第n個元素并回傳被洗掉元素
ElemType delSomeElem(struct List *L,int n){
ElemType x = L->list[n-1];
if(n>L->length){
printf("n位置越界,不能洗掉");
exit(1);
}
for(int i=n;i<L->length;i++){
L->list[i-1] = L->list[i];
}
L->length--;
return x;
}
//從線性表L中洗掉值為X的第一個元素
int delElemKnown(struct List *L,ElemType x){
int i,j;
for(i=0;i<L->length;i++){
if(L->list[i]==x){
break;
}
}
for(j=i;j<L->length;j++){
L->list[j]=L->list[j+1];
}
L->length--;
return 1;
}
/**
* =======修改操作=========
*/
//把線性表中第n個元素修改為x
int updateElemKnown(struct List *L,ElemType x,int n){
if(n>L->length||n<1){
return 0;
}
L->list[n]=x;
return 1;
}
/**
* =======查找操作=========
*/
//查找第n個位置的值
int getElem(struct List *L,int n){
if(n<0||n>L->MaxSize){
printf("查找位置超出長度!\n");
exit(1);
}
return L->list[n-1]; //n-1的原因是查找的第n個是從1開始計數,而陣列是從0開始計數
}
//順序遍歷輸出所有值
void getAll(struct List *L){
int i = 0;
while(i<L->length){
printf("%d\t",L->list[i]);
i++;
}
printf("\n");
}
//查找值為x的節點并回傳其坐標
int findElem(struct List *L,ElemType x){
int i;
for(i=0;i<L->length;i++){
if(L->list[i]==x){
return i;
}
}
}
//主函式
int main()
{
//初始化操作測驗
struct List L;
initList(&L,20);
//插入操作測驗
insertElemToHead(&L,2);
insertElemSomewhere(&L,4,2);
insertElemToTail(&L,5);
printf("%d\n",L.list[0]);
printf("%d\n",L.list[1]);
//洗掉操作測驗
delElemKnown(&L,2);
printf("%d\n",L.list[0]);
//修改操作測驗
updateElemKnown(&L,8,1);
//查找操作測驗
printf("%d\n",getElem(&L,2));
printf("%d\n",findElem(&L,8));
printf("%d\n",L.list[0]);
getAll(&L);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/43000.html
標籤:C++
上一篇:C++中不引人矚目的細節
