数据结构(一) 顺序结构ADT List基本操作函数

完成任何一个操作,都需要函数的调用,而数据结构这本书在写算法前需要将基本操作函数写好

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为地址空间

}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值