严蔚敏版数据结构学习笔记(1):线性表的顺序表示和实现

线性结构的特点:在数据元素的非空有限集合中(1)存在唯一的一个被称作“第一个”的数据元素,(2)存在唯一的一个被称作“最后一个”的数据元素,(3)除第一个外,集合中的每一个数据元素均只有一个前驱,(4)除最后一个数据元素外,每一个元素均只有一个后继。

一个线性表是n个数据元素的有限序列。线性表的数据元素个数n(n>=0)定义为线性表的长度,n=0时称为空表。对一个线性表不仅可以进行访问,还可以进行插入和删除的操作。

例题2-1:假设利用两个线性表LA和LB分别表示两个集合A和B,现在要求一个新的集合A=A U B。

分析:此时在这个题目里面有如下的操作:(1)扩大线性表LA(2)将存于LB而不存于LA中的数据元素插入到LA中


void union(SqList &LA,SqList LB){//将所有不在LA中但是存在于LB中的数据元素插入到LA中 
    Int LA_len = ListLength(LA);
    Int LB_len = ListLength(LB);
    for(int i = 0;iif(!LocateElem(LA,e,equal))///LA中不存在和e相同的数据元素
            ListInsert(LA,++LA_len,e) // 插入
    }

例题2-2:已知线性表LA和LB中的元素按照值非递减的有序排列,现要求合并LA和LB为LC然后将各个数据元素任然按值非递减有序排列。
分析:只要先设一个新的线性表LC为新表,然后依次将LA和LB的元素存入LC即可,所以可以设两个指针i和j分别指向LA和LB中的某个元素,若i所指的元素为a,j所指的元素为b,那么当a>b时,c的取值为b,当a<=b时,c的取值是a;显然指针i和j的初始值都是1,在所指元素插入到LC中以后,在LA或者LB中顺序后移。

Status Mergelist(SqList LA,SqList LB,SqList &LC){//已知线性表LA和LB中的元素按照值非递减排列,LC也按照非递减排列 
    InitLIst(LC);
    int i= j=1;k=0;
    ElemType LA_len=ListLength(lA);
    ElemType LB_len=ListLength(LB);
    while((i<=LA_len)&&(j<=LB_len)) {//LA 和 LB均为非空 
        GetElem(lA,i,ai);
        GetElem(LB,j,bj);
        if(ai<=bj){
            ListIntert(LC,++k,ai);
            ++i;
        }else{
            ListInsert(LC,++k,bj);
            ++j;
        }
    } 
    while(i<=LA_len){
        GetElem(LA,i++,ai);
        ListInsert(LC,++K,ai); 
    }
    while(j<=LB_len){
        GetElem(LB,j++,bj);
        ListInsert(LC,++K,bj);
    }

} 

对于顺序表的合并,上述的算法的基本操作是“元素赋值”,时间复杂度为O(LA.length+LB.length),该算法还可以改写成如下的算法:

void MergeList(SqList LA,SqList LB,SqList &LC){
    ElemType *pa,*pb,*pc,*pa_last,*pb_last;
    pa = LA.elem;
    pb = Lb.elem;
    LC.listsize = LC.length = LA.length+LB.length;
    pc = LC.elem = (ElemType*)malloc(LC.listsize*sizeof(ElemType));
    if(!LC.elem)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++;// 插入LA的剩余元素
    while(pb <= Pb_last)*pc++ = *pb++;// 插入LB的剩余元素
}

该算法具有线性的时间复杂度,原因是(1):由于LA和LB中的数据元素值是递增的(同一集合中元素不等),则对LB中的每个元素,不需要在LA中从表头到表尾进行全程搜索;(2)由于用新表LC表示并集,则插入实际的操作时通过复制来进行的。其时间复杂度是O(nlogn)。
附录:ADT LIST的各个算法的实现:
ADT List{
基本操作:
InitList(&L)//构造一个空表
DestroyList(&L)//销毁线性表L
ClearList(&L)//将L重置为一个空表
ListEmpty(L)//若L为空表,则返回TRUE,否则返回FALSE
ListLength(L)//返回表L的长度(即为L的数据元素个数)
GetElem(L,i,&e)//用e返回L中第i个元素的值
LocateElem(L,e,compare())//返回L中第一个与e满足关系compare()的数据元素的位序,若这样的数据元素不存在,返回值为0
PriorElem(L,cur_e,&pre_e)//若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无意义
NextElem(L,cur_e,&next_e)//若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无意义
ListInsert(&L,i,e)//在线性表L的第i个位置上插入新的数据元素e,L的长度加1
ListDelete(&L,i,&e)//删除L的第i个数据元素,并用e返回其值,L的长度减1
ListTraverse(L,visit())//依次对L的每个数据元素调用visit(),一旦visit()失败,则操作失败
}ADT List
InitList(&L):

Status InitList(SqList& L){//构造一个空的线性表 
    L.elem=(ElemType *)malloc(MAX_SIZE*sizeof(ELemType));//申请内存空间
    if(!L.elem) return ERROR;
    else{
        L.length = 0;
        L.listsize= MAX_SIZE;
        return OK; 
    } 
}

DestroyList(&L):

void DestroyList(SqList &L){//销毁L 
    if(L.elem)
        free(L.elem);//释放线性表占据的所有存储空间
}

ClearList(&L):

void ClearList(Sqlist &L){//清空L 
    L.length=0;//将线性表的长度置为0
}

ListEmpty(L):

Status ListEmpty(SqList L){
    if(L.length==0)return TRUE;
    else return FALSE;
}

ListLength(L):

Status ListLength(L){
    return L.length;
} 

GetElem(L,i,&e):

Stutas GetElem(SqList L,int i,ElemType e){//初始条件:顺序线性表L已存在,1≤i≤ListLength(L)用e返回L中第i个数据元素的值,注意i指位置,第1个位置的数组是从0开始
    if(L.length==0||i<0||i>L.length) return ERROR;
    else{
        *e = L.elem[i-1];
        return OK;
    }
}

LocateElem(L,e,compare()):

Status LocateElem(SqList L,ElemType e,Status(*compare)(int a,int b)){//返回L中第一个大于e的数据元素的位序 实现一
    for(i=0;i<=L.length-1;i++){
        if(compare(L.elem[i],e)==Ok) {
              return i;
              break;
        }else{
            continue;
        } 
    }
    if(i==L.length-1&&(*compare)(L.elem[L.length-1],e)==FALSE)
         return 0;
}
int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType)){
    int i=1;
    ElemType *p = L.elem;
    while(i<=L.length&&!(*compare)(*p++,e)){
              ++i;
         }
    if(i<=L.length) return i;
    else return 0;

}

PriorElem(L,cur_e,&pre_e):

Status PriorElem(SqList L,ElemType cur_e,ElemType *pre_e){//实现一 
    int i=2;
    ElemType *p = L.elem+1;//将p初始为L的第二个元素
    while(i<=L.length&&*p!=cur_e){//从第二个元素开始,挨个与cur_e比较,直到相等或L的最后
        p++;
        i++;    
    }
    if(i>L.length) return ERROR;
    else {
        *pre_e = *--p;//将p的前一个元素赋值给pre_e
        return OK;
    }

}
Status PriorElem(SqList L, ElemType cur_e, ElemType *pre_e) //实现二 
{
    int i;
    int *p = L.elem;
    for (i=0; ilength; i++,p++){//顺序表长度已知,故用for循环
        if (i==0 && *p==cur_e) return ERROR;//此为第一个前驱 
        if (*p == cur_e){     //找到了当前元素且不是第一个元素,
            *pre_e = *--p;      //将其前驱赋给引用参数
            return OK;
      }
    }
}

NextElem(L,cur_e,&next_e):

Status NextElem(SqList L,ElemType cur_e,ElemType *next_e){//实现一 
    int i=1;
    ElemType *p = L.elem;
    while(ilength&&*p!=cur_e){
        p++;
        i--;
    }
    if(i==L.length) return ERROR;
    else{
        *next_e=*++p;
        return OK; 
    }
}
Status NextElem(sqlist L, int cur_e, int *nex_e){//最后一个元素无后继
    int i;
    int *p = L.elem;
     for (i=0; ilength; i++) {//顺序表长度已知,故用for
        if (i==L.length-1 || *p==cur_e) return ERROR;//当前元素为最后一个元素,无后继
        if (*p == cur_e){
             *nex_e = *++p;   //将后继赋给引用参数带回
             return OK;
        }
    }
}

ListInsert(&L,i,e):

Status ListInsert(SqList &L,int i,ElemType e){//在线性表L的第i个位置之前插入新的元素e,i的合法值为1<=i<=ListLength(L)+1;
    if(i<0||i>L.ListLength+1) return ERROR;//i值不合法 
    else{
        if(L.length>=L.listsize){//当前存贮空间已经满了,增加分配 
            ElemType *newbase = (ElemType*)realloc(L.elem,L.length+LISTINCREMENT)*sizeof(ElemType));  
            if(!newbase) return ERROR;
            else{
                L.elem = newbase;
                L.listsize += LISTINCREMENT;
            }
        }
        q = &(L.elem[i-1]);//q为插入位置
        for(p = &(L.elem[L.length-1]);p>=q;--p) *(p+1)=*p;//插入位置及之后的元素位置后移 
        *q = e;  // 插入e
        ++L.length;// 表长增1
        return OK; 
    } 
}

ListDelete(&L,i,&e):

Status ListDelete(SqList &L,int i,ElemType &e){//在顺序线性表L中删除第i个元素,并用e返回其值 ,i的合法值是1<=i<=ListLength(L);
    if(i<1||i>L.length) return ERROR;
    else{
        p = &(L.elem[i-1]); //p为被删除元素的位置 
        e = *p;//把被删除的元素的位置赋值给e 
        q = L.elem+L.length-1;//表尾元素的位置 
        for(++p;p<=q;++p){
            *(p-1)=p;//被删除的元素之后的元素左移
            --L.length;//表长减1
        } 
        return OK; 
    } 
}

ListTraverse(L,visit()):

Status TravelList(SqList L,void(*visit)(SqList*)){
    ElemType *p = L.elem;
    int i = 1;
    while(i
    return OK;
}

上述代码里面提到的compare():

Stauts compare(int a,int b){
    if(a>b) return OK;
    else ERROR;
}

visit()只是个遍历的伪代码随你自己操作而定义。比如你定义个void visit(ElemType *L){printf(“%d”, L.elem[i]) ;} 输出该位置线性表的数据元素

你可能感兴趣的:(严蔚敏版数据结构代码实现)