数据结构--线性表

前言

数据结构在两年前就学过了但以前都是走马观花,现在重拾起来,总结归纳,最后把各种结构和算法用c重写一遍。

线性表的定义

抽象数据类型定义

ADT 线性表(List)
Data
    在数据元素的非空有限集中,存在唯一一个首元素(有唯一的后继)和唯一一个末尾元素(有唯一的前驱),其他中间元素(有唯一前驱和后继)。数据元素之间的关系是一对一的关系。

Operation
    InitList(*L):初始化操作,建立一个空的线性表。
    DestryList(*L);销毁线性表
    ClearList(*L):线性表清空。
    ListEmpty(L):若线性表为空,返回true,否则返回false。
    ListLength(L):返回线性表L的元素个数。
    GetElem(L,i,*e):将线性表L中第i个位置元素返回给e。
    LocateElem(L,e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中的序列号;否则,返回0表示失败。
    PriorElem(L,cur_e,&pre_e);若cur_e是L的元素且不是第一个元素则用per_e返回它的前驱
    NextElem(L,cur_e,&next_e);若cur_e是L的元素,且不是最后一个元素,则用next_e返回它的后继
    ListInsert(*L,i,e):在线性表的第i个位置插入元素e。
    ListDelete(*L,i,*e):删除线性表L中的第i个元素,并用e返回其值
    ListTranverse(L,visit());依次对L的每个元素调用函数visit(),一旦失败则操作失败  

线性表的顺序存储结构

优点:
无需为表中元素之间的逻辑关系增加额外的存储空间,可以快速读取表中的某个位置的元素,时间复杂度O(1)。
缺点:
插入和删除需要移动大量的元素,当线性表的变化很大时候,很难确定线性表的存储空间。容易造成存储空间的碎片化

静态分配

用一组连续地址空间依次存储线性表的数据元素。

typedef struct s_list
{
	ElemTpye data[MAXSIZE];        /* 数据元素 */
	int length;                    /* 线性表当前长度 */
}S_List;

第a个元素和第a+1个元素地址关系: LOC(a+1)=LOC(a)+sizeof(ElemTpye );
第a个元素和第1个元素地址关系: LOC(a)=LOC(1)+sizeof(ElemTpye )*(i-1);

代码实现

#include<stdio.h>
#define MAXSIZE 100
#if MAXSIZE<=0 || MAXSIZE>100
#error error maxsize
#endif

typedef  int ElemTpye;
typedef struct s_list
{
	ElemTpye data[MAXSIZE];        /* 数据元素 */
	int length;                    /* 线性表当前长度 */
}S_List;

typedef enum MyEnum
{
	OK = 0,//操作成功
	ERROR,
	EMPTY,//空
	NO_EMPTY,//非空

	OVER_FLOW,//溢出
USE_UNDEFOP//使用未定义操作

}RESULT;
/*
@breaf  建立一个空的线性表
@param  线性表指针
@return  RESULT
*/
RESULT InitList(S_List *L)
{
	L->length = 0;
	return OK;
}
/*
@breaf  销毁线性表
@param  L[in]线性表指针
@return  RESULT
*/
RESULT DestryList(S_List *L)
{
	return  USE_UNDEFOP;
}
/*
@breaf  清空线性表
@param   L[in]线性表指针
@return  RESULT
*/
RESULT ClearList(S_List *L)
{
	return InitList(L);
}
/*
@breaf  判断线性表是否为空
@param   L[in]线性表
@return  RESULT
*/
RESULT ListEmpty(S_List L)
{
	if (L.length == 0)
		return OK;
	return NO_EMPTY;
}
/*
@breaf  获得线性表长度
@param   L[in]线性表
@return  线性表长度
*/
int ListLength(S_List L)
{
	return  L.length;
}
/*
@breaf  将线性表L中的第i个位置元素返回给e
@param  L[in]线性表
@param  i[in]位置
@param  e[out]查找的元素
*/
RESULT GetElem(S_List L, int i, int *e)
{
	if (ListEmpty(L) == OK)
		return  EMPTY;
	if (L.length>MAXSIZE|| i<1 || i>L.length)
		return OVER_FLOW;
	*e = L.data[i - 1];

	return OK;
}

/*
@breaf  在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中的序列号。
@param   L[in]线性表
@param  e[in]查找的元素
@return 序列号,-1为失败
*/
int LocateElem(S_List L, ElemTpye e)
{
	if (ListEmpty(L) == OK)
		return  -1;

	while (L.length--)
	{
		if (L.data[L.length] == e)
			return L.length+1;
	}
	return -1;

}
/*
@breaf  若cur_e是L的元素且不是第一个元素则用per_e返回它的前驱
@param   L[in]线性表
@param   cur_e[in]查找的元素
@param   pre_e[out]返回前驱的元素
@return  RESULT
*/
RESULT PriorElem(S_List L, ElemTpye cur_e, ElemTpye *pre_e)
{
	int i = LocateElem(L, cur_e);
	if (i <= 1)
		return ERROR;
	*pre_e = L.data[i - 1-1];
	return  OK;
}
/*
@breaf  若cur_e是L的元素且不是最后一个元素则用per_e返回它的后继
@param   L[in]线性表
@param   cur_e[in]查找的元素
@param   pre_e[out]返回后继的元素
@return  RESULT
*/
RESULT NextElem(S_List L, ElemTpye cur_e, ElemTpye *pre_e)
{
	int i = LocateElem(L, cur_e);
	if (i <= 0 || i==L.length)
		return ERROR;
	*pre_e = L.data[i];
	return  OK;
}
/*
@breaf  在线性表的第i个位置插入元素e
@param   L[in]线性表
@param   i[in]序列号
@param   e[in]插入的元素
@return  RESULT
*/
RESULT ListInsert(S_List *L, int i, ElemTpye e)
{
	int k;
	if (ListEmpty(*L) == OK)
		return  EMPTY;
	if (L->length+1>MAXSIZE || i<1 || i>L->length+1)/*插入后没有超出最大长度,插入位置无溢出*/
		return OVER_FLOW;
	if (i <= L->length)        /* 若插入数据位置不在表尾 */
	{
		for (k = L->length - 1; k >= i - 1; k--)  /* 将要插入位置之后的数据元素向后移动一位 */
			L->data[k + 1] = L->data[k];
	}
	L->data[i - 1] = e;          /* 将新元素插入 */
	L->length++;
	return OK;
}


/*
@breaf   删除线性表L中的第i个元素,并用e返回其值
@param   L[in]线性表
@param   i[in]序列号
@param   e[out]删除的元素
@return  RESULT
*/
RESULT ListDelete(S_List *L, int  i, ElemTpye *e)
{
	int k;
	if (ListEmpty(*L) == OK)
		return  EMPTY;
	if (L->length >MAXSIZE || i<1 || i>L->length )
		return OVER_FLOW;
	*e = L->data[i - 1];
	if (i<L->length)                /* 如果删除不是最后位置 */
	{
		for (k = i; k<L->length; k++)/* 将删除位置后继元素前移 */
			L->data[k - 1] = L->data[k];
	}
	L->length--;
	return OK;
}

/*
@breaf   依次对L的每个元素调用函数visit(),一旦失败则操作失败
@param   L[in]线性表
@param   visit[in]需要操作的函数指针
@return  RESULT
*/
RESULT ListTranverse(S_List L, RESULT(* visit)(ElemTpye e))
{
	int i = 0;
	while (i != L.length)
	{
		if (visit(L.data[i++]) != OK)
			return ERROR;
	}
	return OK;
}
动态分配

使用堆区动态分配线性表

typedef struct a_list
{
	ElemTpye *data;  //数据元素指针
	int length;      //当前长度
	int maxsize;     //存储容量
}A_List;
/*
@breaf  建立一个空的线性表
@param  线性表指针
@return  RESULT
*/
RESULT InitList(A_List *L)
{
	L->data = (ElemTpye *)malloc(sizeof(ElemTpye)*MAXSIZE);
	if (!L->data)
		return  MALL_ERR;
	L->length = 0;
	L->maxsize = MAXSIZE;
	return OK;
}
。。。。。。。。

总结

1,插入一个元素所需移动元素次数: n/2
2,删除一个元素所需移动元素次数:(n-1)/2
3,对于两个无序线性表合并,其时间复杂度为O(a.length * b.length)
4,对于两个有序线性表合并,其时间复杂度为O(a.length + b.length)
5,查找时间复杂度O(1)
6,插入删除的时间复杂度O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工农村贴膜小哥

我倒是要看看是那个憨憨在给我打

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值