线性表的抽象数据类型描述
操作集:线性表∈List,元素X∈ElementType,线性表的基本操作有:
- List MakeEmpty () :初始化空线性表
- ElementType FindKth ( int k, List l )
- int FindElement ( Element x, List l)
- void InsertElement ( Element x, int i, List l)
- void DeletElement ( int i, List l)
- int getLength ( List l)
线性表的线性存储方式
线性表的顺序存储实现
typedef struct LNODE *List;
struct LNODE {
ElementType Data[MAXSIZE];
int last;//表示线性表的最后一个元素
};
struct LNODE l;
List PtrL;
//访问下标为i的变量 l.Data[i] / PtrL -> Data[i]
//返回线性表的长度 l.last + 1 / Ptrl -> last + 1
主要操作的实现
1.初始化(创建空的线性表)
//初始化线性表(建立空的顺序表)
List MakeEmpty() {
List Ptrl;
Ptrl = (List) malloc (sizeof (struct LNODE));
Ptrl -> last = -1;
//last = 0表示指向第一个元素,last = -1表示没有元素
return Ptrl;
}
2.查找
int Find(ElementType x,List l) {
int i = 0;
while(i <= Ptrl->last && Ptrl->Data[i] != x) i++;
if(i > Ptrl->last) return -1;//没找到,返回-1
else return i;//找到,返回其位置
//查找成功的平均比较次数为 (n+1)/2 ,时间性能O(n)
}
3.插入
void Insert( List L, ElementType X, int i) { /* 在L的指定位置i前插入一个新元素X */
if ( L->Last == MAXSIZE-1) { /* 表空间已满,不能插入 */
printf("表满");
return;
}
if ( i<0 || Ptrl -> Last+1 ) { /* 检查插入位置的合法性 */
printf("位置不合法");
return;
}
//从后往前移
/*如果把后移数组元素的循环改为for ( j = i-1; j <= PtrL->Last; j++ ) PtrL->Data[j+1]=PtrL->Data[j];
则Data[i-1]到Data[Ptrl -> last]均为原来的Data[i-1]*/
for( j = L->Last; j>=P; j-- )
L->Data[j+1] = L->Data[j]; /* 将位置P及以后的元素顺序向后移动 */
L->Data[i] = X; /* 新元素插入 */
L->Last++; /* Last仍指向最后元素 */
return;
//平均移动次数n/2 时间复杂度O(n)
}
4.删除
/* 删除 */
void Delete( List L, int i ) { /* 从L中删除指定位置P的元素 */
if( i < 0 || i > L->Last ) { /* 检查空表及删除位置的合法性 */
printf("位置%d不存在元素", i );
return;
}
for( int j = i+1; j <= L->Last; j++ )
L->Data[i-1] = L->Data[i]; /* 将位置P+1及以后的元素顺序向前移动 */
L->Last--; /* Last仍指向最后元素 */
return;
//平均移动次数(n-1)/2 时间复杂度O(n)
}
线性表的链式存储实现
主要操作的实现
1.求表长
/*求表长*/
int getLength(List Ptrl) {
List p = Ptrl;//p指向表的第一个结点
int j = 0;
while(p) {//循环条件:p != NULL 即链表未结束
p = p -> Next;
j++;//当前p指向第j个结点
}
return j;
//时间复杂度O(n)
}
2.查找
(1)按序号找
List FindKth (int K, List Ptrl) {
List p = Ptrl;//将p赋为表头
int i = 1;
while(p != NULL && i < k) {
p = p -> Next;
i++;
}
if(i==k) return p;//返回指针
else return NULL;
}
(2)按值查找
Lis Find(ElementType x, List Ptrl) {
List p = Ptrl;//将p赋为表头
while(p!=NULL && p->Data != x)
p = p -> Next;
return p;
}
3.插入(在第i-1个结点后插入一个值为x的新结点)
①构造一个新的结点,用s指向
②找到链表的第i-1个结点,用p指向
③修改指针,插入结点(p之后插入新结点是s)
若两个赋值语句顺序交换,则p -> Next 指向p,故不能正确完成插入
List insert(ElementType x, int i, List Ptrl) {
List p,s;
if( i==1 ) { //新结点插在表头上
s = (List)malloc(sizeof(struct LNode)); //申请、填装新结点
s -> Data = x;
s -> Next = Ptrl;
return s; //返回新表头指针
}
p = FindKth(i-1, Ptrl); //查找第i-1个结点
if( p == NULL ) { //第i-1个结点不存在,不能插入
printf("参数报错");
return NULL;
}
else {
s = (List)malloc(sizeof(struct LNode)); //申请、填装结点
s -> Data = x;
s -> Next = p -> Next; //新结点插入在第i-1个结点后面
p -> Next = s;
return Ptrl;
}
}
4.删除
①找到链表的i-1个结点,用p指向
②用s指针指向要被删除的结点
③修改指针,删除s指向的结点
④释放s所指结点的空间
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);//查找第I-1个结点
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;
}
}
广义表与多重链表
广义表
线性表的推广
广义表中的元素可能是单元素也可能是另一个广义表
//广义表的构建
typedef struct GNode *Glist;
struct GNode{
int Tag; //标志域,0表示结点是单元素,1表示结点是广义表
union { //子表指针域Sublist与单元素数据域Data复用,即公用存储空间
ElementType Data;
GList SubList;
} GRegion;
GList Next; //指向后继结点
};
多重链表
链表中的某个结点可能隶属于多个链表