/*
线性表的优点:查找,存取(对一个元素的改变,实际上也是查找)的速度为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++;
}
}