文章目录
数据结构:
1.数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
2.数据元素相互之间存在的关系称为结构。
3.四种基本结构:集合,线性结构,树形结构,图状结构。
线性结构:
在数据元素的非空有限集中:
1.存在唯一的一个被称作第一个的数据元素。
2.存在唯一的一个被称为最后一个的数据元素。
3.除第一个之外,集合中的每个数据元素均只有一个前驱。
4.除最后一个之外,集合中的每个数据元素均只有一个后继。
线性表:
1.线性表属于线性结构,线性表是数据结构,线性表是n个数据元素的有限序列。
2.线性表的长度:线性表中元素的个数n,n=0时为空表。
3.非空表中每个数据元素都有一个确定的位置,a1是第一个数据元素,an是最后一个数据元素。ai是第i个数据元素,称i为数据元素ai在线性表中的位序。
4.可对线性表的数据元素进行访问,插入,删除等操作。
顺序表:
1.顺序表就是线性表的顺序表示,用一组地址连续的存储单元依次存储线性表的数据元素。
2.线性表第i个数据元素ai的存储位置:
每个元素占用l个存储单元,LOC(a1)是线性表第一个数据元素a1的存储位置,称为线性表的起始位置。
3.顺序表是顺序存储,因为元素在计算机内物理位置相邻。
4.顺序表可以随机存取,存取是一种操作,我们只要知道了线性表的起始地址,那么可以访问线性表中任一数据元素。
顺序表的实现及操作:
1.定义一个顺序表
链表元素的类型是LElemType_Sq,elem是一个类型为LElemType_Sq的指针,我们让它指向第一个元素。也就相当于数组名。
length表示当前链表存入的元素个数。
listsize表示当前链表最多能存几个数。
总的来看,顺序表非常像数组,我们定义一个数组LElemType_Sq a[100],这里a就相当于elem,而且listsize=100,可见顺序表无非是增加了一个length,那么至于为什么增加length,是因为线性表的长度可变,我们要根据length的值改变最大存储空间listsize的值,以达到动态分配数组大小的目的。
typedef struct
{
LElemType_Sq *elem;
int length;
int listsize;
}SqList;
2.构造一个空的顺序表
分配大小为存储LIST_INIT_SIZE个数据元素的空间,相当于给一个一维数组分配空间。
exit()函数是终止进程,不会执行接下来的代码了。
我们初始化时候定了一个最大的存储空间listsize = LIST_INIT_SIZE。
然后让length=0,相当于没存数。
Status InitList_Sq(SqList &L)
{
L.elem = (LElemType_Sq*)malloc(LIST_INIT_SIZE*sizeof(LElemType_Sq));
if(!L.elem)
exit(OVERFLOW);
L.length = 0;
L.listsize = LIST_INIT_SIZE;
return OK;
}
3.在顺序表L第i个位置前插入新元素e
第一个元素的是第一个位置,我们在第i个位置前插入新元素e,那么这个新元素e在第i个位置,也就是说,e是下标为i-1的元素。
参数的意思:L是我们要操作的顺序表,i是我们想要在第i个位置上插入元素,e是我们要插入的元素。
首先插入的话,我们要先判断他的插入位置是否合法,元素可以插到第一个位置或者第length+1个位置。如果元素没插到这个位置范围内,那么错误。还有,如果当前length已经等于或者大于最大存储元素的个数listsize,那么此时我们需要增加空间,从而使e能插入到第length+1个位置。
我们增加空间采用realloc函数,这个函数可以直接在原来定义的那部分内存空间后面增加一部分内存空间。这里我们让他增加能存LISTINCREMENT个元素的内存空间。
然后基址指向这片新的空间,而且listsize需要加上LISTINCREMENT,因为它最大存储元素个数增加了LISTINCREMENT。
我们在第i个位置插入元素,首先要找到这个位置,然后最后一个元素到这个位置的元素统统向后移一个位置,这样的话这个位置才能空出来,然后我们把e放到这个位置。
之前我们都说了,这个和数组很类似。数组下标从0开始,也就是说a[0]指的是第一个元素。那么我们找第i个位置,也就是说找下标为i-1的元素的地址,也就是&a[i-1]。其中a是L.elem,第i个位置的元素地址为q= &(L.elem[i-1])。那么最后一个元素的地址为p=&(L.elem[L.length-1])。
我们用一个for循环,p后移一个位置相当于把p位置的元素赋值给p+1位置的元素,也就是*(p+1)=*p
。每次移动完之后,该移当前位置p之前的那个元素,指向它的指针也就是p-1。直到移完第i个位置的元素。此时我们都移动完了最后一个元素到第i个位置的元素,把e赋值给第i个位置q即可,然后length加一,因为多了个元素。
Status ListInsert_Sq(SqList &L, int i, LElemType_Sq e)
{
LElemType_Sq *newbase;
LElemType_Sq *p, *q;
if(i<1 || i>L.length+1)
return ERROR;
if(L.length >= L.listsize)
{
newbase = (LElemType_Sq*)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof(LElemType_Sq));
if(!newbase)
exit(OVERFLOW);
L.elem = newbase;
L.listsize += LISTINCREMENT;
}
q = &(L.elem[i-1]);
for(p=&(L.elem[L.length-1]); p>=q; --p)
*(p+1) = *p;
*q = e;
L.length++;
return OK;
}
4.在顺序表L中删除第i个元素,并用e返回其值
删除我们先判断删除位置是否合法,合法的位置范围在第一个位置,和第length个位置之间,超过了这个范围就错误。
删除的话是第i+1个元素移到第i个元素,然后后面元素依次往前移,直到第length个元素移到第length-1个元素。那我们for循环的话,也是从第i+1个元素开始,循环到第length个元素,每次循环,当前元素的值赋值给上一个元素的值。最后length–,因为删去了一个数。
Status ListDelete_Sq(SqList &L, int i, LElemType_Sq &e)
{
LElemType_Sq *p, *q;
if(i<1 || i>L.length)
return ERROR;
p = &L.elem[i-1];
e = *p;
q = L.elem+L.length-1;
for(++p; p<=q; ++p)
*(p-1) = *p;
L.length--;
return OK;
}
5.在顺序表L中查找第1个值与e满足compare()的元素的位序
这里面用了一个函数指针,Status(*Compare)(LElemType_Sq, LElemType_Sq)
这个我用c++编译器发现Compare不加*
也是正确的。大概是重载的缘故。用这个函数指针好处就是,我们可以通过每次调用不同的compare函数,实现自定义的比较方式。
当compare函数返回true时,也就是说已经找到满足条件的元素了,此时,我们直接跳出循环,如果没有还需继续找下一个元素,i+1。
i是当前找的第几个元素,最大不能超过第length个元素,第i个元素的值是L.elem[i-1]。
Status CmpGreater(LElemType_Sq e, LElemType_Sq data)
{
return data>e ? TRUE : FALSE;
}
Status Cmp(LElemType_Sq e, LElemType_Sq data)
{
return data==e ? TRUE : FALSE;
}
int LocateElem_Sq(SqList L, LElemType_Sq e, Status(*Compare)(LElemType_Sq, LElemType_Sq))
{
int i = 1;
while(i<=L.length && !Compare(e, L.elem[i-1]))
++i;
if(i<=L.length)
return i;
else
return 0;
}
6.合并顺序表,按值非递减排列
合并的话,首先是给了两个按值非递减排列的顺序表,让存到另外一个顺序表里,这个新顺序表也是按值非递减排列。
这个新顺序表Lc需要存储的元素个数是La.length + Lb.length。而且由于它大小已经确定了,所以listsize直接等于La.length + Lb.length,然后我们给Lc分配内存空间,能存Lc.listsize个元素。
由于要确定边界条件以及当前位置,我们需要直到La,Lb,Lc的首地址pa,pb,pc,以及La,Lb的最后一个元素的地址pa_last,pb_last。
然后开始合并,比较La,Lb的大小,小的存到pc的当前的位置上,然后pc的和小的那个的当前位置加一,表示继续往下进行,从下一个位置开始比较,存放到pc下一个位置。直到La或Lb之中有一个已经找完了,那么此时我们就把没找完的放到pc里面即可。
void MergeSqList_Sq(SqList La, SqList Lb, SqList &Lc)
{
LElemType_Sq *pa, *pb, *pc;
LElemType_Sq *pa_last, *pb_last;
pa = La.elem;
pb = Lb.elem;
Lc.listsize = Lc.length = La.length + Lb.length;
pc = Lc.elem = (LElemType_Sq *)malloc(Lc.listsize*sizeof(LElemType_Sq));
if(!pc)
exit(OVERFLOW);
pa_last = La.elem + La.length - 1;
pb_last = Lb.elem + Lb.length - 1;
while(pa<=pa_last && pb<=pb_last)
{
if(*pa <= *pb)
*pc++ = *pa++;
else
*pc++ = *pb++;
}
while(pa <= pa_last)
*pc++ = *pa++;
while(pb <= pb_last)
*pc++ = *pb++;
}
顺序表操作实例及代码:
代码:
#include<cstdio>
#include<cstdlib>
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define UNDERFLOW -3
#define TRUE 1
#define FALSE 0
typedef int LElemType_Sq;
typedef int Status;
typedef struct
{
LElemType_Sq *elem;
int length;
int listsize;
}SqList;
Status InitList_Sq(SqList &L)
{
L.elem = (LElemType_Sq*)malloc(LIST_INIT_SIZE*sizeof(LElemType_Sq));
if(!L.elem)
exit(OVERFLOW);
L.length = 0;
L.listsize = LIST_INIT_SIZE;
return OK;
}
Status ListInsert_Sq(SqList &L, int i, LElemType_Sq e)
{
LElemType_Sq *newbase;
LElemType_Sq *p, *q;
if(i<1 || i>L.length+1)
return ERROR;
if(L.length >= L.listsize)
{
newbase = (LElemType_Sq*)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof(LElemType_Sq));
if(!newbase)
exit(OVERFLOW);
L.elem = newbase;
L.listsize += LISTINCREMENT;
}
q = &(L.elem[i-1]);
for(p=&(L.elem[L.length-1]); p>=q; --p)
*(p+1) = *p;
*q = e;
L.length++;
return OK;
}
Status ListDelete_Sq(SqList &L, int i, LElemType_Sq &e)
{
LElemType_Sq *p, *q;
if(i<1 || i>L.length)
return ERROR;
p = &L.elem[i-1];
e = *p;
q = L.elem+L.length-1;
for(++p; p<=q; ++p)
*(p-1) = *p;
L.length--;
return OK;
}
int LocateElem_Sq(SqList L, LElemType_Sq e, Status(*Compare)(LElemType_Sq, LElemType_Sq))
{
int i = 1;
while(i<=L.length && !Compare(e, L.elem[i-1]))
++i;
if(i<=L.length)
return i;
else
return 0;
}
void MergeSqList_Sq(SqList La, SqList Lb, SqList &Lc)
{
LElemType_Sq *pa, *pb, *pc;
LElemType_Sq *pa_last, *pb_last;
pa = La.elem;
pb = Lb.elem;
Lc.listsize = Lc.length = La.length + Lb.length;
pc = Lc.elem = (LElemType_Sq *)malloc(Lc.listsize*sizeof(LElemType_Sq));
if(!pc)
exit(OVERFLOW);
pa_last = La.elem + La.length - 1;
pb_last = Lb.elem + Lb.length - 1;
while(pa<=pa_last && pb<=pb_last)
{
if(*pa <= *pb)
*pc++ = *pa++;
else
*pc++ = *pb++;
}
while(pa <= pa_last)
*pc++ = *pa++;
while(pb <= pb_last)
*pc++ = *pb++;
}
Status ListTraverse_Sq(SqList L, void(Visit)(LElemType_Sq))
{
int i;
for(i=0; i<L.length; i++)
Visit(L.elem[i]);
printf("\n");
return OK;
}
void PrintElem(LElemType_Sq e)
{
printf("%d ", e);
}
Status CmpGreater(LElemType_Sq e, LElemType_Sq data)
{
return data>e ? TRUE : FALSE;
}
Status Cmp(LElemType_Sq e, LElemType_Sq data)
{
return data==e ? TRUE : FALSE;
}
int main(){
SqList La, Lb, Lc;
LElemType_Sq a[4] = {1, 2, 3, 5};
LElemType_Sq b[7] = {2, 2, 3, 4, 5, 6, 7};
int i,j;
InitList_Sq(La);
for(i=1; i<=4; i++)
ListInsert_Sq(La, i, a[i-1]);
InitList_Sq(Lb);
for(i=1; i<=7; i++)
ListInsert_Sq(Lb, i, b[i-1]);
printf("La操作前 = ");
ListTraverse_Sq(La, PrintElem);
printf("Lb操作前 = ");
ListTraverse_Sq(Lb, PrintElem);
printf("\n");
MergeSqList_Sq(La, Lb, Lc);
printf("合并La和Lb为Lc = ");
ListTraverse_Sq(Lc, PrintElem);
printf("\n");
LElemType_Sq e;
ListDelete_Sq(Lc, 6, e);
printf("删除 Lc 中第 6 个元素 %d\n", e);
printf(" Lc 中的元素为:Lc = ");
ListTraverse_Sq(Lc, PrintElem);
printf("\n");
i = LocateElem_Sq(Lc, 3, CmpGreater);
printf(" Lc 中第一个元素值大于 \"3\" 的元素的位置为 %d ", i);
j = LocateElem_Sq(Lc, 3, Cmp);
printf(" Lc 中第一个元素值等于 \"3\" 的元素的位置为 %d ", j);
}
运行结果:
La操作前 = 1 2 3 5
Lb操作前 = 2 2 3 4 5 6 7
合并La和Lb为Lc = 1 2 2 2 3 3 4 5 5 6 7
删除 Lc 中第 6 个元素 3
Lc 中的元素为:Lc = 1 2 2 2 3 4 5 5 6 7
Lc 中第一个元素值大于 “3” 的元素的位置为 6 Lc 中第一个元素值等于 “3” 的元素的位置为 5