C语言数据结构与算法
一.线性表
1.线性表的顺序结构
#define MAXSIZE 100
typedef struct
{
ElemType elem[MAXSIZE];
int last;
}SeqList;
2.顺序表的查找操作
(1)按序号查找:即按照下标顺序查找
(1)按内容查找:按照elem的内容查找,从第一个元素开始,找到最后的last,若查找成功则返回该元素的序号,若为成功则返回-1,代码如下:
int Locate(SeqList L,ElemType e)
{
int i=0;
while((i<=L.last)&&(L.elem[i]!=e))
i++;
if(i<=L.last)
return i+1;
else
return (-1);//没有找到
}//一定注意,数组的下标和元素的序号仍有一定差别,元素序号=角标+1
3.线性表的插入操作
即在第i个位置插入新的元素,原有的元素依次向后移动一个单位,代码如下:
#define OK 1
#define ERROR 0
int InsertList(SeqList*L,ElemType e,int i)//这里不再是只读模式,而是要改变元素的地址,所以要传入指针
{
int k;
if((i<1)||(i>L->last+2))
{
printf("插入位置i值非法");
return(ERROR);
}
if(L->last>=MAXSIZE-1)
{
printf("表已满,无法插入");
return(ERROR);
}
for(k=L->last;k>=i-1;k--)
L->elem[k+1]=L->elm[k];//将后一个位置的元素替换成前一个位置的元素
L->elem[i-1]=e;//插入成功
L->last++;
return(OK);
}
$$
Eins(插入一个元素的平均移动次数)=n/2
$$
4.线性表的删除操作:
将要删除的元素存储到一个指针当中
int DelList(SeqList* L,int i,ElemType* e)
{
int k;
if((i<1)||(i>L->last+2))
{
printf("删除位置非法");
return(ERROR);
}
*e=L->elme[i-1];
for(k=i;k<=L->last;k++)
L->elem[k+1]=L->elem[k];//同意向后移动
L->last--;
return (OK);
}
$$
Edel(删除一个元素的平均移动次数)=n-1/2
$$
5.线性表的合并操作
将A和B线性表合并成为C,其中A,B均为非递减有序排列,要求C也是非递减有序排列,代码如下:
void MergeList(SeqList* A,SeqList* B,SeqList* C)
{
int i=0,k=0,j=0;
while(i<=A->last&&j<=B->last)
if(A->elme[i]<=B->elme[j])//将A插入C中
{
C->elme[k]=A->elme[i];
k++;i++;
}
else //将B插入C中
{
C->elme[k]=B->elme[j];
k++;j++;
}
while(i<=A->last)//代表B先插完
{
C->elme[k]=A->elme[i];
i++;k++;
}
while(i<=B->last)//代表A先插完
{
C->elme[k]=B->elme[j];
j++;k++;
}
C->last=A->last+B->last+1;//两个线性表合并要+1,三个线性表合并要+2,以此类推
}
算法分析:时间复杂度为O(A->last+B->last)
6.顺序表的优缺点
优点1:无须为表示结点间的逻辑关系而增加额外的存储空间,因为逻辑上相邻的元素其存储的物理位置是相邻的
优点2:可以方便的随机存取表中的任意元素
缺点1:插入或删除效率太低,除表尾外,在表的其他节点进行删除或插入均需要移动大量节点;
缺点2:在存储空间满后需要额外扩展空间,其每次分配的空间相对来说还是静态空间,需要调用函数接口才能实现扩容
PS一下容量问题的控制
#define MAXSIZE 100
typedef struct
{
ElemType elem[MAXSIZE];
int last;//last+1其实就是容量
}SeqList;
所以我们可以这样改进
#define MAXSIZE 100
typedef struct
{
ElemType* elem;
int size;//当前装的元素的个数
int capcity;//绝对容量
}SeqList;
当然其它函数的参数也会相应改变,在每次调用其他函数(尤其是插入)时需要判断一下线性表是否溢出可以这样判断:
if (L->size == L->capcity)
{
int newcapcity = (L->capcity == 0 ? 4 : L->capcity * 2);//是0给4,其他情况直接扩容两倍
ElemType* cur = (ElemType*)realloc(L->a, newcapcity * sizeof(ElemType));//realloc是在原有的基础上继续扩容
if (cur == NULL)
{
perror((const char*)cur);
exit(-1);
}
L->elem = cur;//elme得到新的地址用于管理新的空间
L->capcity = newcapcity;
}