完成任何一个操作,都需要函数的调用,而数据结构这本书在写算法前需要将基本操作函数写好
ADT List如下:
ADT List
{
数据对象:D = {ai|ai∈ElemSet,i=1, 2, …, n, n≥0}
数据关系:R = {<ai-1, a>|ai-1, ai∈D, i=2, …, n}
基本操作:
//1.初始化、销毁和清空操作
InitList( &L )
操作结果:构造一个空的线性表L
DestroyList( &L )
初始条件:线性表L已存在
操作结果:销毁线性表
ClearList( &L )
初始条件:线性表L已存在
操作结果:将线性表L重置为空表
//2.访问型操作
ListEmpty( L )
初始条件:线性表L已存在
操作结果:若线性表L为空表,则返回TRUE,否则返回FALSE
ListLength( L )
初始条件:线性表L已存在
操作结果:返回线性表L的元素个数
GetElem( L, i, &e )
初始条件:线性表L已存在,且1≤i≤ListLength(L)
操作结果:用参数e返回线性表L中第i个元素的值
LocateElem( L, e )
初始条件:线性表已存在
操作结果:返回线性表L中第一个与参数e相同的数据元素的位置。若这样的元素不存在,则返回0
PriorElem( L, cur_e, &pre_e )
初始条件:线性表L已存在
操作结果:若cur_e是线性表L中的数据元素,且不是第一个元素,则用pre_e返回其前驱元素,否则操作失败,pre_e无意义
ListTraverse( L )
初始条件:线性表L已存在
操作结果:从线性表第一个元素开始,依次访问并输出线性表的数据元素
//3.加工型操作
SetElem( &L, i, &e )
初始条件:线性表L已存在,且1≤i≤ListLength(L)
操作结果:将线性表L中第1个元素的值用参数e替换,并将旧值用参数e返回
InsertElem( &L, i, e )
初始条件:线性表L已存在,且1≤i≤ListLength(L)+1
操作结果:将线性表L中第i个元素的值用参数e替换,并将旧值用参数返回
DeleteElem( &L, i, &e )
初始条件:线性表L已存在,且1≤i≤ListLength(L)
操作结果:删除线性表L中第i个位置上的数据元素,并用参数e返回其元素值,原来第i+1个到第n个元素依次向前移动一个位置,线性表L的长度减1
} //ADT List
顺序结构基本操作函数
所展示的代码在数据结构(严蔚敏版)书上基本都是可以找到的,在首次编写时最重要的是写好数据的结构,其基本思路都很简单,利用位序来获取元素位置
//c++_set_list
#include <iostream>
#include <stdlib.h>
using namespace std;
#define ListInitSize 128 //初次分配空间大小
#define ListIncrement 256 //空间增量大小
typedef struct List
{
int* pData;
// 指向一个地址 //动态存储空间的基地址
int length;
//个数 //存储数据元素的个数
int size;
//大小 //当前已分配的存储空间的大小
}List;
//构造一个空的线性表
void InitLIst(List& L)
{
//动态分配内存空间
L.pData = (int*)malloc(ListInitSize * sizeof(int));
if (L.pData==NULL)
{
exit(1);
}
L.length = 0;//个数为0,即无变量
L.size = ListInitSize;//为空线性表赋大小
}
//若线性表存在,则销毁线性表,即释放内存
void DestroyList(List L)
{
if(L.pData != NULL)
{
free(L.pData);
L.pData = NULL;
}
L.length = 0;
L.size = 0;
}
//若线性表存在,则清空线性表
void ClearList(List& L)
{
if(L.pData!=NULL)
{
L.length = 0;
}
}
//1、这里需要注意的是List& L引用了地址,其在函数调用的过程中,L会因函数的操作,其值会被真实改变
//2、List L只是一个形参变量,不会改变其地址等真实内容
//若L为空表,则返回TURE,否则返回FALSE
bool ListEmpty(List L)//注意当返回值为True False时,函数的类型为bool型
{ //判断顺序表是否为空表
if (L.length == 0) //顺序表长度为0
return true;
else
return false;
}
//返回L的数据元素个数
int ListLength(List L)
{
return L.length;
}
//利用副本e来返回L中的第i个元素
int GetElem(List L,int i,int& e)//引用?地址
{
if (i < 1 || i > L.length) //参数检查
cout << "error1" << endl;
e = L.pData[i - 1]; //获得数据元素
return e;
}
//查找e的元素位序
int LocatElem(List L,int e)
{
for(int i = 0;i<=L.length;i++)
{
if(L.pData[i] == e) return i;
}
return 0;
}
//如果在cur_e为L的非第一个元素,pre_e返回前驱
int PriorElem(List L,int cur_e,int& pre_e)
{
if(cur_e != L.pData[0])
{
for(int i = 0;i<=L.length;i++)
{
if(L.pData[i] == cur_e) pre_e = L.pData[i+1];
}
return pre_e;
}
else
cout<<"操作失败,pre_e未定义"<<endl;
return 0;
}
//如果cur_为L中的元素,且不是最后一个,则返回后驱
int NextELem(List L,int cur_e,int& next_e)
{
if(cur_e != L.pData[L.length-1])//长度非0,但下标从0开始,终止位序应减1
{
for(int i = 0;i<=L.length;i++)
{
if(L.pData[i] == cur_e) next_e = L.pData[i-1];
}
return next_e;
}
else
cout<<"操作失败,pre_e未定义"<<endl;
return 0;
}
void ListInsert(List& L, int i, int e)
{ //在顺序表第i个位置上插入数据元素e
if (i < 1 || i > L.length + 1) //参数检查
cout << "error2" << endl;
if (L.length >= L.size) //当前存储空间已满,需增加存储空间
{
int* newbase = (int*)realloc(L.pData, (L.size + ListIncrement) * sizeof(int));
if (newbase == NULL)
cout << "error3" << endl; //内存申请失败
L.pData = newbase;
L.size += ListIncrement;
}
//从最后一个元素开始,直到下标为i-1(物理位置)的元素,依次向后挪一个位置
for (int j = L.length - 1; j >= i - 1; j--)
L.pData[j + 1] = L.pData[j];
L.pData[i - 1] = e; //在数组下标为i-1的位置上插入元素e
L.length += 1; //顺序表的长度加1
}
//删除元素
int ListDelete(List &L,int i ,int& e)
{
//i为逻辑位序,从1开始,length、i 1-13均为逻辑位序
if(L.pData == NULL || i<1 || i>L.length)
cout<<"长度值超出范围"<<endl;
e = L.pData[i-1];//[]里为物理位序,下标从0开始,将要删除的元素赋值给e
//将删除后的后一个元素循环赋给前一个元素
//循环终止条件:当删除时,总长度减1,循环次数也减1
//循环起始位置:从i位置删除,故在i位置之前,元素不变,所以从i处开始循环,又因为i与length都为逻辑位序,所以不用考虑下标问题,其中i值与length值可相等,均为逻辑位序
for(int j = i;j<=L.length-1;j++)
{
L.pData[j-1] = L.pData[j];
}
L.length--;
return e;
//L.pData[i] = L.pData[i+1];
//free(*L.pData[i+1])
}
//替换元素的值
int SetElem(List& L, int i, int& e)
{
int temp;
temp = L.pData[i];
L.pData[i] = e; //将第i个元素用e替换
e = temp; //用e获取旧值
return e;
} //SetElem
访问并输出每个元素
void ListTraverse(List L)
{
for (int i = 0; i < L.length; i++) //遍历整个顺序表
{
cout << L.pData[i] <<" "; //访问并输出元素
}
cout<<endl;
} //ListTraverse
书上并未给出顺序表赋值的函数,而在算法2.1时需要为顺序表赋值,赋值函数代码如下
//将线性表赋值
void assignment_List(List& L)
{
int i,x,n;
int& e = x;
InitLIst(L);
cout<<"请输入线性表的长度"<<endl;
cin >> n;
cout<<"请输入线性表的元素值"<<endl;
for(i = 1;i<=n;i++)
{
cin >> x;
ListInsert(L,i,e);
}
cout<<"线性表的数据内容如下"<<endl;
ListTraverse(L);
}
以数据结构(严蔚敏版)算法2.1为实例实验并调用以上基本操作函数,鉴于代码行数过多,且函数较多,将其加入头文件,在其调用函数的时候,引入头文件即可,代码如下
//算法2.1__归并算法
#include <stdlib.h>
#include <iostream>
using namespace std;
#include "F:\C-data_sturct\数据结构list\head_file.cpp"
void MergeList(List La,List Lb,List& Lc)
{
int i,j,k,La_len,Lb_len;
int ai,bj;//ai,bj分别表一,表二i,j处返回的值
i=j=1; k=0;
La_len = ListLength(La);
Lb_len = ListLength(Lb);
while(i<=La_len && j<=Lb_len)
{
GetElem(La,i,ai); GetElem(Lb,j,bj);
//当ai<=bj时候,i++,此时j值不变,只有ai>bj时,j++,从而达到错位比较输出表中非每个值
if(ai<=bj)
{
ListInsert(Lc,++k,ai);
++i;
}else
{
ListInsert(Lc,++k,bj);
++j;
}
}
//当上一个循环结束后,i,j已经达到某个值,这是如果i,j小于原长度的时候,将会再次执行循环,以将i之后的值输出
while(i<=La_len)
{
GetElem(La,i++,ai);
ListInsert(Lc,++k,ai);
}
while(j<=Lb_len)
{
GetElem(Lb,j++,bj);
ListInsert(Lc,++k,bj);
}
}
int main()
{
List La,Lb,Lc;
cout<<"a表赋值"<<endl;
assignment_List(La);
//cout<<GetElem(La,i,ai)<<endl;
cout<<"b表赋值"<<endl;
assignment_List(Lb);
InitLIst(Lc);
MergeList(La,Lb,Lc);
ListTraverse(Lc);
}
在此基本函数中主要运用了malloc()、realloc()函数为表开辟内存空间,对其函数理解如下
//内存分配空间函数
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define ListInitSize 128 //初次分配空间大小
#define ListIncrement 256 //空间增量大小
typedef struct List{
int* pData;
int size;
}List;
int main()
{
List L;
//需要注意和明白的是释放内存和开辟内存空间的变量均为指针
/*先释放原来L.pData所指内存区域
并按照(L.listsize+LISTINCREMENT)*sizeof(ElemType)的大小重新分配空间
其中LISTINCREMENT为2(#define LISTINCREMENT 2 ),同时将原有数据从头到尾拷贝到新分配的内存区域,
并返回该内存区域的首地址。即重新分配存储器块。
*/
//realloc()
int* newbase = (int*)realloc(L.pData, (L.size + ListIncrement) * sizeof(int));
//malloc()
//malloc函数格式如下:type *var_name = (type*)malloc(sizeof(type)*num);
L.pData = (int*)malloc(sizeof(int)*ListInitSize);
//L.pdata为一个指针数据类型,元素个数为单个空间大小,再乘上int的字节数大小,其*pdata为地址空间
}