目录
一、线性表的抽象数据类型描述
1、类型名称:
线性表(List)
2、数据对象集:
线性表是n(>=0)个元素构成的有序序列
3、操作集:
线性表LList,整数i表示位置,元素x
ElementType
4、线性比表的基本操作有:
(1)、List MakeEmpty(): 初始化一个空的线性表L
(2)、ElementType FindKth(int K, List L): 根据位序K,返回相应的元素
(3)、int Find(ElementType X, List L): 在线性表L中查找X的第一次出现的位置
(4)、void insert(ElementType X, int i, List L): 在位置 i 前插入一个新元素X
(5)、void Delete(int i, List L): 删除指定位序 i 的元素
(6)、int Length(List L): 返回线性表的长度n
顺序存储结构
//这里是用数组来进行线性表的表示!!!
//初始化(建立空的顺序表)
List MakeEmpty()
{
List PtrL;
PtrL=(List)malloc(sizeof(struct LNode));
PtrL->Last=-1;
return PtrL;
}
//查找
int Find(ElenmentType X,List PtrL)
{
int i=0;
while(i <= PtrL->Last && PtrL->Data[i]!=X )
i++;
if(i >PtrL->Last) return -1; /*如果没有找到,返回-1*/
else return i; /*如果找到了,返回的就是存储位置*/
}
//插入(先移动后插入)
void Insert(ElementType X,int i,List PtrL)
{
int j;
if(PtrL->Last == MAXSIAE-1){ //表空间已经满了就不可以再插入了,如果是用链表来表示线性表
printf("表满"); //就不用判断满没满
return;
if(i<1 || i>PtrL->Last+2){
printf("位置不合法");
return;
}
for(j=PtrL->Last ; j>=i ; j--){ //如果符合插入条件,就需要把插入位置后的元素全部后移
PtrL->Data[j+1]=PtrL->Data[j]; //进行移动
}
PtrL->Data[i-1]=X; //把X进行插入
PtrL->Last++; //Last指向最后一个元素
return ;
}
//删除(操作顺序和插入相反)
void Delete(int i;List PtrL)
{
int j;
if(i<1 || i>PtrL->Last+1){ //检查删除位置的合法性
printf("不存在第%d个元素",i);
return ;
}
for(j=i ; j<=PtrL->Last ; j++){
PtrL->Data[j-1]=PtrL->Data[j]; //将要删除后的元素向前移动
}
PtrL->Last--; //Last仍然指向最后的元素
return ;
}
插入(第 i (1<= i <=n+1)个位置前插入一个值为X的新元素)
下标 i | 0 | 1 | ...... | i-1 | ...... | n-1 | ...... | MAXSIZE-1 | |
Data | a1 | a2 | ...... | ai | ...... | an(Last指向的地方) | ...... | -- |
先移动后插入:
下标 i | 0 | 1 | ...... | i | i | n-1 | ...... | n | MAXSIZE-1 |
Data | a1 | a2 | ...... | ai | a n-1 | ...... | an(现在Last指向的位置) | -- |
二、简单链表基础操作
1、求表长
int Length(List PtrL)
{
List p=PtrL; //p指向第一个结点
int i=0;
while(p){
p=p->Next;
i++; //当前p指向的是第i个结点
}
return i;
}
2、查找
(1)、按照序号查找FindKth
List FindKth(int K,List PtrL)
{
List p=PtrL;
int i=1;
while(p!=NULL && i<K){
p=p->Next;
i++;
}
if(i==K)
{
return p; //找到第K个,然后返回指针
}else{
return NULL; //否则返回空
}
}
(2)、按照值查找Find
List Find(ElementType X,List PtrL){
List p=PtrL;
while(p!=NULL && p->Data!=X){
p=p->Next;
}
return p;
}
3、插入操作的实现
List Insert(Element X,int i,List PtrL){
List p=PtrL;
if(i==1){ //新结点插入在表头
s=(List)malloc(size(struct LNode)); //申请、填装新结点
s->Data=X;
s->Next=PtrL;
return s; //返回新表头指针
}
p=FindKth(i-1,PtrL); //查找第i-1个结点
if(p=NULL){ //第i-1个结点不存在,所以不可以插入
printf("参考i错");
return NULL;
}else{
s=(List)malloc(sizeof(struct LNode)); //申请、填装结点
s->Data=X;
s->Next=p->Next; //新添加的结点在i-1后面
p->Next=s;
return PtrL;
}
}
4、删除操作的实现
List Delete(int i,List PtrL)
{
List p,s;
if(i==1) { //如果要删除第一个结点
s=PtrL; //s指向第一个结点
if(PtrL!=NULL){
PtrL=PtrL->Next; //从链表中删除
}else{
return NULL;
}
free(s); //释放被删除的结点
return PtrL;
}
p=FindKth(i-1,PtrL)
if(p==NULL){
printf("第%d个结点不存在",i-1);
return NULL;
}else if(p->Next==NULL){
printf("第%d个结点不存在",i);
return NULL;
}else{
s=p->Next; //s指向第i个结点
p->Next=s->Next; //从列表中删除
free(s); //释放被删除的结点
return PtrL;
}
}
二、广义表
1、举个例子
用链表表示二元多项式:
解析:可以将上面的二元多项式看成是关于x的一元多项式(有点了类似换元法)
及为:
二元多项式可以用“复杂”的链表来表示
2、广义表的定义
(1)、广义表是线性表的推广;
(2)、对于线性表而言,n个元素都是基本的单元素;
(3)、广义表中,这些元素不仅可以是单元素也可以是另一个广义表。
typedef struct GNode*GList;
struct GNode{
int Tag; //标志域:0表示结点是单元素,1表示结点是广义表
union{ //子表指针域Sublist与单元素数据域Data复用,即共用存储空间
ElementType Data;
GList SubList;
}URegion;
GList Next; //指向后继结点
};
这个域可能是不能分解的单元,也可能是一个指针
三、多重链表
1、多重链表的定义
(1)、多重链表:链表中的结点可能同时隶属于多个链表;
(2)、多重链表中的结点的指针域会有多个,如广义表中的Next和SubList两个指针域;
(3)、但是包含的两个指针域的链表并不一定是多重链表,可能是双向链表而不是多重链表,所以两个指针域多重链表。
(4)、多重链表用途广泛:基本上如树、图这样相对复杂的数据结构都可以采用多重链表方式进行存储。
2、举个例子
用多重链表表示矩阵
解析:一般看到矩阵我们都会想到用二维数组来进行表示,但是数组是有缺陷的:数组的大小是事先确定的;对于“稀疏矩阵”,将造成大量的存储空间浪费。所以我们现在采取一种典型的多重链表——十字链表
十字链表的具体操作:
(1)、只存储矩阵中非0的元素项;
(2)、结点的数据域:行坐标Row、列坐标Col、数值Value
(3)、每个结点通过两个指针域,把同行、同列串起来
行指针(或者称为向右指针)Right
列指针(或者称为向下指针):Down
(4)、用一个Tag来区分头结点和非0元素结点
(5)、头节点的标识值为“Head”,矩阵非0元素结点的标识值为“Term”