資料結構二:線性表的順序結構實現
阿新 • • 發佈:2019-02-13
此程式根據高一凡大神的源程式修改而成。
/************************************************************* FileName:c2-1.h Function:定義線性表的動態分配順序儲存結構(動態分配的一維陣列) *************************************************************/ #pragma once #ifndef __C2_1_H__ #define __C2_1_H__ #define LIST_INIT_SIZE 10 // 線性表儲存空間的初始分配量 #define LIST_INCREMENT 2 // 線性表儲存空間的分配增量 typedef int ElemType; //定義抽象資料型別ElemType在本程式中為整型 struct SqList { ElemType * elem; // 儲存空間基址 int length; // 當前長度 int listsize; // 當前分配的儲存容量(以sizeof(ElemType)為單位) }; #endif
/************************************************************* FileName:bo2-1.h Function:順序表示的線性表的基本操作(12個),包括演算法2.3,2.4,2.5,2.6 *************************************************************/ #pragma once #ifndef _BO2_1_H__ #define _BO2_1_H__ #include "c1.h" #include "c2-1.h" // 構造一個空的順序線性表 void InitList_Sq(SqList &L); // 銷燬順序線性表L void DestroyList_Sq(SqList &L); // 將順序線性表L重置為空表 void ClearList_Sq(SqList &L); // 操作結果:若 L為空表,則返回 TRUE;否則返回 FALSE Status ListEmpty_Sq(SqList L); // 返回順序順序線性表中資料元素的個數 int ListLength_Sq(SqList L); // 用e返回L中第i個數據元素的值 Status GetElem_Sq(SqList L, int i, ElemType &e); // 返回L中第一個與e滿足關係compare()的資料元素的位序 int LocateElem_Sq(SqList L, ElemType e, Status (*compare)(ElemType, ElemType)); // 若cur_e是L的資料元素,且不是第一個,則用pre_e返回它的前驅 Status PriorElem_Sq(SqList L, ElemType cur_e, ElemType &pre_e); // 若cur_e是L的資料元素,且不是最後一個,則用next_e返回它的後繼 Status NextElem_Sq(SqList L, ElemType cur_e, ElemType &next_e); // 在L中第i個位置之前插入新的資料元素e,L的長度加1 Status ListInsert_Sq(SqList &L, int i, ElemType e); // 刪除L的第i個數據元素,並用e返回其值,L的長度減1 Status ListDelete_Sq(SqList &L, int i, ElemType &e); // 依次對L的每個資料元素呼叫函式vi() void ListTraverse_Sq(SqList L, void (*vi)(ElemType &)); #endif
/******************************************************************* FileName:bo2-1.cpp Function:實現順序表示的線性表的基本操作(12個),包括演算法2.3,2.4,2.5,2.6 *******************************************************************/ #include "c2-1.h" #include "bo2-1.h" #include "c1.h" // 構造一個空的順序線性表 void InitList_Sq(SqList &L) { L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType)); if( !L.elem ) exit(OVERFLOW); // 記憶體分配失敗 L.length = 0; // 空表長度為0 L.listsize = LIST_INIT_SIZE; // 初始儲存容量 } // 銷燬順序線性表L void DestroyList_Sq(SqList &L) { free(L.elem); L.elem = NULL; L.length = 0; L.listsize = 0; } // 將順序線性表L重置為空表 void ClearList_Sq(SqList &L) { L.length = 0; } // 操作結果:若 L為空表,則返回 TRUE;否則返回 FALSE Status ListEmpty_Sq(SqList L) { if( L.length == 0 ) return TRUE; else return FALSE; } // 返回順序順序線性表中資料元素的個數 int ListLength_Sq(SqList L) { return L.length; } // 用e返回L中第i個數據元素的值 Status GetElem_Sq(SqList L, int i, ElemType &e) { if( i < 1 || i > L.length ) return ERROR; e = *(L.elem + i - 1); return OK; } // 返回L中第一個與e滿足關係compare()的資料元素的位序 int LocateElem_Sq(SqList L, ElemType e, Status (*compare)(ElemType, ElemType)) { ElemType * p; int i = 1; // i的初值為第1個元素的位序 p = L.elem; // p的初值為第1個元素的儲存位置 while( i <= L.length && !compare(*p++, e) ) i ++; if( i <= L.length ) return i; else return 0; // 表示未找到與e匹配的資料元素 } // 若cur_e是L的資料元素,且不是第一個,則用pre_e返回它的前驅 Status PriorElem_Sq(SqList L, ElemType cur_e, ElemType &pre_e) { int i = 2; ElemType * p = L.elem + 1; while( i <= L.length && *p != cur_e ){ p ++; i ++; } if( i > L.length ) return INFEASIBLE; // 操作失敗 else{ pre_e = *(--p); return OK; } } // 若cur_e是L的資料元素,且不是最後一個,則用next_e返回它的後繼 Status NextElem_Sq(SqList L, ElemType cur_e, ElemType &next_e) { int i = 1; ElemType *p = L.elem; while( i < L.length && *p != cur_e ){ i ++; p ++; } if( i == L.length ) return INFEASIBLE; // 操作失敗 else{ next_e = *(++p); return OK; } } // 在L中第i個位置之前插入新的資料元素e,L的長度加1 Status ListInsert_Sq(SqList &L, int i, ElemType e) { ElemType * newbase, *q, *p; if( (i < 1) || (i > L.length + 1) ) // i值不合法 return ERROR; if( L.length >= L.listsize ){ // 當前儲存空間已滿,增加分配 if( !(newbase = (ElemType *)realloc(L.elem, (L.listsize + LIST_INCREMENT) * sizeof(ElemType))) ) exit(OVERFLOW); // 記憶體分配失敗 L.elem = newbase; // 新基址 L.listsize += LIST_INCREMENT; // 增加儲存容量 } q = L.elem + i - 1; // q為插入位置 // 插入位置及其之後的元素右移 for( p = L.elem + L.length - 1; p >= q; p -- ) *(p+1) = *p; *q = e; // 插入e L.length ++; // 表長增加1 return OK; } // 刪除L的第i個數據元素,並用e返回其值,L的長度減1 Status ListDelete_Sq(SqList &L, int i, ElemType &e) { ElemType *p, *q; if( (i < 1) || (i > L.length) ) return ERROR; p = L.elem + i - 1; // p為被刪除的元素的位置 e = *p; // 被刪除的元素的值賦給e q = L.elem + L.length - 1; // 表尾的元素 for( ++ p; p <= q; ++ p) // 被刪除元素之後的元素左移 *(--p) = *p; L.length --; // 表長減1 return OK; } // 依次對L的每個資料元素呼叫函式vi() void ListTraverse_Sq(SqList L, void (*vi)(ElemType &)) { ElemType *p; int i; p = L.elem; for( i = 1; i <= L.length; i ++ ) vi(*p++); }
/**************************************************
FileName:func2-3.h
Function: 測試順序線性表中使用的幾個常用的函式
**************************************************/
#pragma once
#ifndef __FUNC2_3__
#define __FUNC2_3__
#include "c1.h"
#include "c2-1.h"
// 判斷是否相等的函式
Status equal(ElemType c1,ElemType c2);
// 根據 a<、 =或 >b,分別返回 -1、 0或 1
int comp(ElemType a,ElemType b);
void print(ElemType c);
void print2(ElemType c);
void print1(ElemType &c);
#endif
/**************************************************
FileName:func2-3.cpp
Function: 實現測試順序線性表中使用的幾個常用的函式
**************************************************/
#include "func2-3.h"
#include "c2-1.h"
#include <stdio.h>
// 判斷是否相等的函式
Status equal(ElemType c1, ElemType c2)
{
if(c1==c2)
return TRUE;
else
return FALSE;
}
// 根據 a<、 =或 >b,分別返回 -1、 0或 1
int comp(ElemType a, ElemType b)
{
if(a==b)
return 0;
else
return (a-b) / abs(a-b);
}
void print(ElemType c)
{
printf("%d ", c);
}
void print2(ElemType c)
{
printf("%c ", c);
}
void print1(ElemType &c)
{
printf("%d ", c);
}
/**********************************************
Function: 定義結果狀態值(OK...)
包含常用標頭檔案
Description: 包含的標頭檔案很多,實際使用的時候
自行修改
**********************************************/
#pragma once
#ifndef __C1_H__
#define __C1_H__
#include<string.h>
#include<ctype.h>
#include<malloc.h> // malloc()等
#include<limits.h> // INT_MAX等
#include<stdio.h> // EOF(=^Z或F6),NULL
#include<stdlib.h> // atoi()
#include<io.h> // eof()
#include<math.h> // floor(),ceil(),abs()
#include<process.h> // exit()
#include<iostream> // cout cin
//函式結果狀態程式碼
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
// #define OVERFLOW -2因為在math.h中已定義OVERFLOW的值為3,故去掉此行
typedef int Status; // Status是函式的型別,其值是函式結果狀態程式碼,如OK等
typedef int Boolean;// Boolean是布林型別,其值是TRUE或FALSE
#endif
/********************************************************
FileName: main2-1.cpp
Function: 測試順序線性表的12種操作函式
********************************************************/
#include "c1.h"
#include "c2-1.h"
#include "bo2-1.h"
#include "func2-3.h"
// 資料元素判定函式 (平方關係 ) , LocateElem() 呼叫的函式
Status sq(ElemType c1, ElemType c2);
// ListTraverse() 呼叫的另一函式 (元素值加倍 )
void dbl(ElemType &c);
void main()
{
SqList L;
ElemType e,e0;
Status i;
int j,k;
// 測試初始化線性表的函式:InitList_Sq()
InitList_Sq(L);
printf("初始化 L後: L.elem=%u L.length=%d L.listsize=%d\n\n",L.elem,L.length,L.listsize);
// 通過在表頭前插入元素,測試插入新元素的函式:ListInsert_Sq()
for(j=1;j<=5;j++)
i=ListInsert_Sq(L,1,j);
printf("在 L的表頭依次插入 1~ 5後: *L.elem=");
for(j=1;j<=5;j++)
std::cout<<*(L.elem+j-1)<< ' ';
std::cout<<std::endl;
printf("L.elem=%u L.length=%d L.listsize=%d\n\n",L.elem,L.length,L.listsize);
// 測試判斷線性表是否為空的函式:ListEmpty_Sq()
i=ListEmpty_Sq(L);
printf("L是否空: i=%d(1: 是 0: 否 )\n\n",i);
// 測試清空線性表的函式:ClearList_Sq()
ClearList_Sq(L);
printf("清空 L後: L.elem=%u L.length=%d L.listsize=%d",L.elem,L.length,L.listsize);
i=ListEmpty_Sq(L);
printf("L是否空: i=%d(1: 是 0: 否 )\n\n",i);
// 通過在表尾後插入元素,測試插入新元素的函式:ListInsert_Sq()
for(j=1;j<=10;j++)
ListInsert_Sq(L,j,j);
printf("在 L的表尾依次插入 1~ 10後: *L.elem=");
for(j=1;j<=10;j++)
std::cout<<*(L.elem+j-1)<< ' ' ;
std::cout<<std::endl;
printf("L.elem=%u L.length=%d L.listsize=%d\n",L.elem,L.length,L.listsize);
// 測試當插入的資料元素超過初始分配的記憶體空間的情況
ListInsert_Sq(L,1,0);
printf("在 L的表頭插入 0後: *L.elem=");
for(j=1; j<=ListLength_Sq(L); j++) // ListLength(L) 為元素個數
std::cout<<*(L.elem+j-1)<< ' ' ;
std::cout<<std::endl;
printf("L.elem=%u(有可能改變 ) L.length=%d(改變 ) L.listsize=%d(改變 )\n\n", L.elem, L.length, L.listsize);
// 測試獲取線性表元素的函式:GetElem_Sq()
GetElem_Sq(L,6,e);
printf("第 6個元素的值為 %d\n\n",e);
// 測試返回L中第一個與e滿足關係compare()的資料元素的位序的函式:LocateElem_Sq()
for(j=10;j<=11;j++)
{
k=LocateElem_Sq(L,j,equal);
if(k) // k不為 0,表明有符合條件的元素,且其位序為 k
printf("第 %d個元素的值為 %d\n",k,j);
else
printf("沒有值為 %d的元素 \n",j);
}
for(j=3;j<=4;j++)
{
k=LocateElem_Sq(L,j,sq);
if(k) // k不為 0,表明有符合條件的元素,且其位序為 k
printf("第 %d個元素的值為 %d的平方 \n",k,j);
else
printf("沒有值為 %d的平方的元素 \n",j);
}
// 測試找前驅的函式:PriorElem_Sq()
for( j=1; j<=2; j++ ) // 測試頭兩個資料
{
GetElem_Sq(L, j, e0); // 把第 j個數據賦給 e0
i=PriorElem_Sq(L, e0, e); // 求 e0的前驅
if( i == INFEASIBLE )
printf("元素 %d無前驅 \n",e0);
else
printf("元素 %d的前驅為 %d\n",e0,e);
}
// 測試找後繼的函式:NextElem_Sq()
for( j = ListLength_Sq(L) - 1; j <= ListLength_Sq(L); j ++ ) // 最後兩個資料
{
GetElem_Sq(L, j, e0); // 把第 j個數據賦給 e0
i=NextElem_Sq(L, e0, e); // 求 e0的後繼
if(i==INFEASIBLE)
printf("元素 %d無後繼 \n",e0);
else
printf("元素 %d的後繼為 %d\n",e0,e);
}
// 測試刪除線性表元素的函式:ListDelete_Sq()
k=ListLength_Sq(L); // k為表長
for( j = k + 1; j >= k; j --)
{
i = ListDelete_Sq(L, j, e); // 刪除第 j個數據
if( i == ERROR )
printf("\n刪除第 %d個元素失敗 \n",j);
else
printf("刪除第 %d個元素成功,其值為 %d\n\n", j, e);
}
// 測試遍歷線性表的函式:ListTraverse_Sq()
printf("依次輸出 L的元素: ");
ListTraverse_Sq(L, print1); // 依次對元素呼叫 print1() ,輸出元素的值
printf("\n");
printf("L的元素值加倍後: ");
ListTraverse_Sq(L, dbl); // 依次對元素呼叫 dbl() ,元素值乘 2
ListTraverse_Sq(L, print1);
printf("\n\n");
// 測試銷燬線性表的函式:DestroyList_Sq()
DestroyList_Sq(L);
printf("銷燬 L後: L.elem=%u L.length=%d L.listsize=%d\n",L.elem,L.length,L.listsize);
getchar();
}
// 資料元素判定函式 (平方關係 ) , LocateElem() 呼叫的函式
Status sq(ElemType c1, ElemType c2)
{
if(c1 == c2*c2)
return TRUE;
else
return FALSE;
}
// ListTraverse() 呼叫的另一函式 (元素值加倍 )
void dbl(ElemType &c)
{
c *= 2;
}