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

来源:互联网 发布:河北省中标数据网 编辑:程序博客网 时间:2024/06/05 18:42

线性结构的特点:在数据元素的非空有限集合中(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;i<LB_len;i++){        GetElem(LB,i,e);        if(!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; i<L.length; 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(i<L.length&&*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; i<L.length; 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<L.length){        visit(p++);        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]) ;} 输出该位置线性表的数据元素

原创粉丝点击