定义:
若结构时非空有限集,则有且仅有一个开始节点和一个终端节点,并且所有节点最多只有一个直接前驱和一个直接后继。
表达式:(a1,a2,...,an)
特点:
1.只有一个首结点和一个尾结点;
2.除首尾结点外,其他结点只有一个直接前驱和一个直接后继。
总结:
线性结构反应结点之间的关系是一对一的。线性结构包括线性表,堆栈,队列,字符串,数组等。
( a1 , a2 , a3 , ... , ai-1, ai , ai+1 , ... , an )
a1,an分别为线性起点和线性终点。
ai-1是ai的直接前驱,ai+1是ai的直接后继。
1,2,3,...,n 是下标,表示元素在表中的位置
n为元素总个数,即表长。
【注】同一线性表中的元素具有相同特性,元素之间的关系是线性的,比如学生情况登记表。
1.顺序表的顺序表示
用一组地址连续的存储单元依次存储线性表中的数据元素。
( a1 , a2 , a3 , ... , ai-1, ai , ai+1 , ... , an )
a1占据线性表的起始地址,也称为基地址。
2.元素地址计算方法
loc(ai)=loc(a1)+(i-1)*L。
loc表示地址,L表示该线性表中一个元素占用的存储单元*个数。
【注】计算机最小信息单位是bit(一个二进制位),8个bit组成一个byte(字节)。一个存储单元可以存储一个字节,即8个bit。
比如int型数据通常占4个字节,那么L为4。
3.顺序表主要操作的实现
#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;//int重命名为Status,表示状态,即上面宏定义的正确,错误,溢出等
typedef int Elemtype;
Elemtype是元素类型的意思,下面以int为例,也可以使用其他类型。
动态分配的顺序存储结构:
#define LIST_INIT_SIZE 100//线性表存储空间的初始分配量
#define LISTINCREMENT 10//线性表存储空间的初始分配量(空间不足时会用到)
typedef struct
{
Elemtype *elem;//存储空间基地址
int length;//当前表长(即现在表中的元素个数)
int listsize;//当前分配的存储容量(以sizeof(Elemtype)(字节数)为单位)
}SqList;//将上面结构体命名为SqList
顺序表的初始化
Status InitList_Sq(SqList &L)//建空表 status即为int型变量,表示状态
{
L.elem=(Elemtype *)malloc(LIST_INIT_SIZE*sizeof(Elemtype ));//基地址
if(!L.elem) exit(OVERFLOW);//存储分配失败,结束。非零值
L.length=0;//空表长度为0
L.listsize=LIST_INIT_SIZE;//初始存储容量
return OK;//分配成功
}
malloc函数的原型为:void *malloc (unsigned int size);其作用是在内存的动态存储区中分配一个长度为size的个字节的(内存块)连续空间。 以void*类型返回分配的内存区域地址(分配区域的起始地址)。
free函数原型是:void free(void *p); 其作用是释放指针p所指向的内存区。其参数p必须是先前调用malloc函数时返回的指针。
realloc函数原型为void *realloc(void *p,unsigned int size); 如果已经通过malloc函数获得了动态空间 ,想改变其大小,可以用realloc函数重新分配。用realloc函数将p所指向的动态空间的大小改变为size。
L.elem是int*类型,所以需要强制类型转化为int*,才能为它分配对应类型的地址。
!L.elem:当条件为真时,执行内容。if的内容执行,表明!L.elem为1,则L.elem为0.没有分配。
size:以字节为单位,地址也以字节为单位。LIST_ INIT_SIZE可以理解为可容纳的元素个数,元素类型为int型,那么地址大小为LIST_ INIT_SIZE*sizeof (int)。
顺序表的销毁
初始条件:顺序线性表L已存在。
操作结果:销毁顺序线性表L
Status DestroyList(SqList &L)
{
free(L.elem);
L.elem=NULL;
L.length=0;
L.listsize=0;
return OK;
}
顺序表置空
初始条件:顺序线性表L已存在。
操作结果:将L重置为空表
Status ClearList(SqList &L)
{
L.length=0;
printf("长度为",L.length);
return TRUE;
}
顺序表判空
初始条件:顺序线性表L已存在
操作结果:若L为空表,则返回1,否则返回0
Status ListEmpty(SqList &L)
{
if(L.length==0) return 1;
else return 0;
}
顺序表求长
初始条件:顺序线性表L已存在。
操作结果:返回L中数据元素个数
Status ListLength(SqList L)
{
return L.length;
}
返回指定位置元素的值
初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。
操作结果:用e返回L中第i个数据元素的值
Status GetElem(SqList L,int i,Elemtype &e)
{
printf("输入查找元素的位置:");
scanf("%d",&i);
if(i<1||i>L.length) return ERROR;
e=*(L.elem+1-1);
return OK;
}
顺序表的赋值
Status ValueList_Sq(SqList &L)//赋值
{
int i,j;
printf("元素个数:");
scanf("%d",&i);//取地址别忘
if(i>L.listsize)//元素个数大于能容纳的个数
{
L.elem=(Elemtype *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(Elemtype ));
//重新分配空间。当前容量+增量
L.listsize+=LISTINCREMENT;
}
printf("输入元素:");
for(j=0;j
【注】元素下标 ( j ) +1=位序 ( i )。
顺序表的查找:
初始条件:顺序表L已存在, compare( )是比较两个数据元素是否相等的判定函数,相等返回1,不等返回0
操作结果:返回L中第一个与e满足关系compare( )的数据元素的位序,若不存在这样的元素,返回0
Status LocateElem_Sq(SqList L, Elemtype e,Status (*compare)(Elemtype , Elemtype ))
{
Elemtype *p=L.elem; // p 的初值为第 1 元素的存储位置
int i = 1; // i 的初值为第 1 元素的位序
printf("输入查找元素的值:");
scanf("%d",&e);
while (i <= L.length && !(*compare)(*p++, e))
++i;
if (i <= L.length) return i;
else return ERROR;
}
思路:从第一个元素开始,不断比较(*(compare(当前元素,要查找的元素 ),若i <=L.length,如果没找到 !(*compare)(*p++, e),一直向后找(i++)。如果找到, !(*compare)(*p++, e)不满足,则跳出查找操作,返回位序;如果全部遍历仍没找到,返回0。
*p++:使用p取内容的值后p再加1(sizeof(int))
compare是指向函数的指针,函数指针变量指向函数,函数参数类型均为int型。 在编译时,一个函数总是占用一段连续的内存区域,每个函数都有一个入口地址,函数名为该函数所在内存区域的首地址,这和数组名非常类似,把函数的这个首地址(或称为入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。
比如:
Status Equal(Elemtype a,Elemtype b)//相等关系
{
if(a==b) return OK;
else return 0;
}
也可以定义其他关系,比如是否满足a
想判断什么关系,只需将表明关系的函数名(即首地址)赋给*Compare,那么它指向的就是该函数。
printf("%d",LocateElem_Sq(List,e,Equal));
顺序表的插入
初始条件:L存在,1<=i<=L.length+1
操作结果:在表中第i个位置之前插入元素e,表长+1
Status ListInsert_Sq(SqList &L,Elemtype i,Elemtype e)
{
Elemtype *p,*q;//p表示插入位置.p,q与L.elem同类型的指针
Elemtype *newbase;//新分配内存地址
printf("输入要插入的位置和元素的值:");
scanf("%d%d",&i,&e);
if(i<1||i>L.length+1) exit(OVERFLOW);//插入位置不合法
if (L.length >= L.listsize)
{// 当前存储空间已满,增加分配
newbase = (Elemtype *) realloc (L.elem, (L.listsize+LISTINCREMENT)*sizeof (Elemtype ));
if (!newbase) exit(OVERFLOW); // 存储分配失败
L.elem = newbase; // 新基址
L.listsize += LISTINCREMENT; // 增加存储容量
}
p=&(L.elem[i-1]);//取地址
for(q=&L.elem[L.length-1];q>=p;q--) //长度-1表示当前最后一个元素的下标
*(q+1)=*q;//前一个元素值赋给后一个,实现元素顺次后移
*p=e;//给插入元素赋值
++L.length;//别忘了长度+1
return OK;
}
思路:
(1)判断插入位置和是否合法,合法值1≤i≤L.length+1;
(2)判断顺序表的存储空间是否已满( L.length >= L.listsize );
(3)将原表第n至第i 位的元素依次向后移动一个位置,空出第i个位置;
(4)将插入元素放入第i位,表长+1;
指针p确定插入位置为i,反映在数组中下标为i-1,由此确定p值;
q指向要后移的元素。初值为末尾元素地址,*(q+1)为空,从n位到i位依次后移,总有预留空位,避免覆盖;相反就会丢失数据。直到第i个元素移动完毕(q>=p,不要忘记等于,不然第i个元素未被后移)。现在*p就为空,刚好给它赋值,实现插入。
顺序表的删除
初始条件:L存在,1<=i<=L.length
操作结果:删除表中第i个元素,用e返回其值,表长-1
Status ListDelete(SqList &L,int i,Elemtype &e)
{
Elemtype *p,*q;
printf("输入删除元素的位置:");
scanf("%d",&i);
if(i<1||i>L.length) // i值不合法
exit(OVERFLOW);
p=L.elem+i-1; // p为被删除元素的位置,也可以写p=&(L.elem[i-1]);
e=*p; // 被删除元素的值赋给e
q=L.elem+L.length-1; // 表尾元素的位置
for(++p;p<=q;++p) // 被删除元素之后的元素左移。起始为待删除元素的下一位,终止于最后一位元素。
*(p-1)=*p;
printf("删除元素的值为%d",e);
L.length--; // 表长减1
return OK;
}
顺序表的输出
Status PrintList_Sq(SqList &L)//输出
{
int i;
printf("List:");
for(i=0;i
#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;//int重命名为Status,表示状态,即上面宏定义的正确,错误,溢出等
typedef int Elemtype;
#define LIST_INIT_SIZE 100//线性表存储空间的初始分配量
#define LISTINCREMENT 10//线性表存储空间的初始分配量(空间不足时会用到)
typedef struct
{
Elemtype *elem;//存储空间基地址
int length;//当前表长(即现在表中的元素个数)
int listsize;//当前分配的存储容量(以sizeof(Elemtype)(字节数)为单位)
}SqList;//将上面结构体命名为SqList
Status InitList_Sq(SqList &L)//建空表 status即为int型变量,表示状态
{
L.elem=(Elemtype *)malloc(LIST_INIT_SIZE*sizeof(Elemtype ));//基地址
if(!L.elem) exit(OVERFLOW);//存储分配失败,结束。非零值
L.length=0;//空表长度为0
L.listsize=LIST_INIT_SIZE;//初始存储容量
return OK;//分配成功
}
Status DestroyList(SqList &L)
{
free(L.elem);
L.elem=NULL;
L.length=0;
L.listsize=0;
return OK;
}
Status ClearList(SqList &L)
{
L.length=0;
printf("长度为",L.length);
return TRUE;
}
Status ListEmpty(SqList &L)
{
if(L.length==0) return 1;
else return 0;
}
Status ListLength(SqList L)
{
return L.length;
}
Status GetElem(SqList L,int i,Elemtype &e)
{
printf("输入查找元素的位置:");
scanf("%d",&i);
if(i<1||i>L.length) return ERROR;
e=*(L.elem+1-1);
return OK;
}
Status ValueList_Sq(SqList &L)//赋值
{
int i,j;
printf("元素个数:");
scanf("%d",&i);//取地址别忘
if(i>L.listsize)//元素个数大于能容纳的个数
{
L.elem=(Elemtype *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(Elemtype ));
//重新分配空间。当前容量+增量
L.listsize+=LISTINCREMENT;
}
printf("输入元素:");
for(j=0;jL.length+1) exit(OVERFLOW);//插入位置不合法
if (L.length >= L.listsize)
{// 当前存储空间已满,增加分配
newbase = (Elemtype *) realloc (L.elem, (L.listsize+LISTINCREMENT)*sizeof (Elemtype ));
if (!newbase) exit(OVERFLOW); // 存储分配失败
L.elem = newbase; // 新基址
L.listsize += LISTINCREMENT; // 增加存储容量
}
p=&(L.elem[i-1]);//取地址
for(q=&L.elem[L.length-1];q>=p;q--) //长度-1表示当前最后一个元素的下标
*(q+1)=*q;//前一个元素值赋给后一个,实现元素顺次后移
*p=e;//给插入元素赋值
++L.length;//别忘了长度+1
return OK;
}
Status ListDelete(SqList &L,int i,Elemtype &e)
{
Elemtype *p,*q;
printf("输入删除元素的位置:");
scanf("%d",&i);
if(i<1||i>L.length) // i值不合法
exit(OVERFLOW);
p=L.elem+i-1; // p为被删除元素的位置,也可以写p=&(L.elem[i-1]);
e=*p; // 被删除元素的值赋给e
q=L.elem+L.length-1; // 表尾元素的位置
for(++p;p<=q;++p) // 被删除元素之后的元素左移。起始为待删除元素的下一位,终止于最后一位元素。
*(p-1)=*p;
printf("删除元素的值为%d",e);
L.length--; // 表长减1
return OK;
}
Status PrintList_Sq(SqList &L)//输出
{
int i;
printf("List:");
for(i=0;i
运行结果
有错还请多多指教,感谢