线性表list定义与操作

/*
线性表的优点:查找,存取(对一个元素的改变,实际上也是查找)的速度为O(1)
线性表的缺点:插入,删除都需要移动,速度为O(n)
*/



#include<stdio.h>
#define SIZE 100//预定义列表大小
#define INCREMENT 10//列表需要增加容量时的增加量
#define OK 1
#define ERROR 0
typedef int Status;//表示返回的状态值 
typedef int ElemType//int来表示某一种元素类型









//用一个结构体来 描述 List列表
//List列表为动态数组,但是可以进行大小变换,增删,插入
//typedef的作用是将数据类型用一个标志符代替,结构体是一种数据类型
typedef struct
{
	ElemType *elem;//元素类型的指针,用于做数组存储数据
	int length;//线性表的长度
	int listsize;//当前最大容量
}List;


//初始化列表函数,对List的属性进行设置
Status InitialList(List L)
{
	//给列表变量分配内存空间
	L.elem=(ElemType*)malloc(SIZE*sizeof(ElemType));
	if(!L.elem)//如果没有分配成功则执行
	{
		exit(OVERFLOW);//退出程序返回OVERFLOW,exit(0)才是正常返回
	}
	L.length=0;
	L.listsize=SIZE;
	return OK;
}


//插入元素到列表的第i个元素的位置中
// 插入需要平移数组,因此平均时间复杂度为O(n)
Status ListInsert(List &L,ElemType e,int i)
{
	//判断i是否在索引范围内
	if(i>L.length+1||i<1)
	{
		return ERROR;
	}
	//判断容量是否已满,不然扩大容量
	if(L.length==L.listsize)
	{
		//realloc是重新分配一个地址,并将L中的元素copy过去,若成功则释放L.elem返回新地址,失败返回null且L.elem不释放
	    //并判断分配成功与否
		ElemType *newbase;
		newbase=(ElemType*)realloc(L.elem,(L.listsize+INCREMENT)*sizeof(ElemType));
	    if(!newbase)
			exit(OVERFLOW);
	    //地址再赋给L
		L.elem=newbase;
		//修改容量属性
	    L.listsize=L.listsize+INCREMENT;

	}
	//循环实现移位(!!!也可以用索引赋值来实现,此处用指针当索引的方式在用,指针和索引其实是一个东西)
	//*获得指针对应数值,&获得变量指针
	ElemType* p=&(L.elem[i-1])//第i个元素的索引
	ElemType* q=&(L.elem[L.length-1])//最后一个元素的位置
	for(;q>=p;q--)//q的加一减一表示一次加减ElemType类型大小的地址间距
	{
		*(q+1)=*(q);//移位
	}
	//插入元素
    L.elem[i]=e;
    //更新长度
	L.length+=1;
	
	return OK
}



//删除第i个元素(不是索引的第i位)
//因为删除后要平移数组,因此平均时间复杂度为O(n)
Status ListDelete(List &L,int i,ElemType &e)
{
	//判断是否在索引范围内
	if(i>L.length||i<1)
	{
		return ERROR;
	}
	e=L.elem[i-1];
	//直接循环移位覆盖来删除
    ElemType *p=&(L.elem[i-1]);//i-1为第i个元素的索引
    ElemType *q=&(L.elem[L.length-1]);	//最后一个元素的位置
	for(;p<q;p++)
	{
		*p=*(p+1);
	}
	//更新长度
	L.length-=1;
	
	return OK;

	
}

//搜索元素在列表中的位置,若不存在则返回0,存在返回位置值
//Status (*compare)(ElemType,ElemType)为函数指针,是用于传递函数的形参,此处可以接收equal,compare等自定义的比较函数
//逐个比较来判断是否存在e这个元素
//因为要逐个判断,因此平均时间复杂度为O(n)
int LocateElem(List L,ElemType e,Status (*compare)(ElemType,ElemType))
{
	ElemType *p=L.elem;//计录元素在那一位
	while(!(*compare)(*p,e)&&(p-L.elem)<L.length)
	{
		p++;
	}	
	if(p-L.elem==L.length)//如果超出范围即没有查找到
	{
		return 0;
	}
	else
	{
        return p-L.elem+1;
	}
}


//合并两个非递减排序的顺序表
//结论:对线性表进行合并,筛选等等等集合性质的操作时,最好先对线性表进行排序,然后再进行操作
//由于每一位元素都需要循环到,因此时间复杂度为O(两表长度之和),也相当于O(n)
void ListMerge(List L1,List L2,List &L3)
{
	ElemType *p1=L1.elem,*pe1;//获取每一个列表的地址
    ElemType *p2=L2.elem;*pe2;
	ElemType *p3;
	pe1=L1.elem+L1.length;//得到末尾指针pointend
	pe2=L2.elem+L2.length;
	//得到L3的列表大小和长度
	L3.listsize= L3.length=L1.length+L2.length;
	p3=L3.elem=(ElemType*)malloc(L3.length*sizeof(ElemType));
	if(!L3.elem)
	{
		exit(OVERFLOW);
	}
	while(p1!=pe1&&p2!=pe2)//先穿插排序
	{
		if(*p1>*p2)
		{
			*p3=*p2;
			p2++;
		}
		else
		{
			*p3=*p1;
			p1++;
		}
		p3++;
	}
	while(p1<pe1)//判断是否剩余,是则将其加在L3的后面
	{
		*p3=*p1;//此处可以用*p3++=*p2++;代替这三行代码,++优先级更高,先自加,但是++在后面整体不加,因此可以实现效果
		p1++;
		p3++;
	}
	while(p2<pe2)
	{
		*p3=*p2;
		p2++;
		p3++;
	}
}




            
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页