[数据结构]第二章--线性表(读书笔记1)

来源:互联网 发布:移动数据流量包退订 编辑:程序博客网 时间:2024/06/07 09:52

第二章--线性表

2.1 线性表的类型定义

□什么是线性表结构的特点
存在唯一的一个被称作第一个的数据元素。存在唯一的一个被称作最后一个的数据元素,除第一个之外,集合中的每个数据元素均只有一个前驱也均只有一个后继。

□什么是线性表
线性表(linear_list)是最常用且最简单的一种数据结构,简言之一个线性表是n个数据元素的有限序列。在稍复杂的线性表中,一个数据元素可以由若干个数据项(item)组成。

2.2 线性表的顺序表示和实现

□什么是线性表的顺序表示
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻。这种存储结构的弱点是在作插入或删除操作时,需要移动大量的元素。

在顺序存储结构的线性表中插入或者删除一个数据元素,平均约移动表中一半元素。若表长为n,则算法ListInsert_Sq和ListDelete_Sq的时间复杂度为O(n)。

以下是顺序线性表的代码实现:

/* 线性表存储空间的初始分配量 */#define LIST_INIT_SIZE 10/* 线性表存储空间的分配增量 */#define LISTINCREMENT 2/* 顺序存储的线性表*/typedef struct {ElemType *elem;/*存储空间基址*/int length;/*当前长度*/int listsize;/* 当前分配的存储容量(以sizeof(ElemType)为单位) */}SqList;Status InitList(SqList *L) /* 算法2.3 */{ /* 操作结果:构造一个空的顺序线性表 */(*L).elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));if(!(*L).elem){exit(OVERFLOW); /* 存储分配失败 */}(*L).listsize = LIST_INIT_SIZE; /* 初始存储容量 */(*L).length = 0;/* 空表长度为0 */return OK;}Status DestroyList(SqList *L){ /* 初始条件:顺序线性表L已存在。操作结果:销毁顺序线性表L */free((*L).elem);(*L).elem = NULL;(*L).listsize = 0; /* 初始存储容量为0 */(*L).length = 0;/* 空表长度为0 */return OK;}Status ClearList(SqList *L){ /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */(*L).length = 0;/* 空表长度为0 */return OK;}Status ListEmpty(SqList L){/*判断顺序表是否为空表*/if(L.length == 0){return TRUE;}else{return FALSE;}}int ListLength(SqList *L){ /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */return (*L).length;}Status GetElem(SqList L, int i, ElemType *e){/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) *//* 操作结果:用e返回L中第i个数据元素的值 */if (i < 1 || i > ListLength(&L)){return ERROR;}*e = *(L.elem + i - 1);return OK;}int LocateElem(SqList L, ElemType e, Status(*compare)(ElemType,ElemType)){/* 初始条件:顺序线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0) *//* 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 *//*           若这样的数据元素不存在,则返回值为0。算法2.6 */ElemType *p;int count = 1;p = L.elem;while (count <= L.length && !compare(*p++, e) ){++count;}if (count <= L.length){return count;}else{return 0;}}Status PriorElem(SqList L, ElemType cur_e, ElemType *pre_e){/* 初始条件:顺序线性表L已存在 *//* 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, *//*           否则操作失败,pre_e无定义 */ElemType* p = L.elem + 1;int count = 2;/*L的数据元素是从第2个开始*/while(L.length > count && cur_e != *p){count++;p++;}if (count >= L.length){return INFEASIBLE;}else{*pre_e = *--p;return OK;}}Status NextElem(SqList L, ElemType cur_e, ElemType *next_e){/* 初始条件:顺序线性表L已存在 *//* 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, *//*           否则操作失败,next_e无定义 */int i=1;ElemType *p = L.elem;while(i < L.length && *p != cur_e){i++;p++;}if(i == L.length){return INFEASIBLE;}else{*next_e = *++p;return OK;}}Status ListInsert(SqList *L, int i, ElemType e) /* 算法2.4 */{/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1 *//* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */ElemType *newbase = NULL;ElemType *q = NULL;ElemType *p = NULL;ElemType *pEnd = (*L).elem + (*L).length - 1;/*判断i值是否合法*/if(i < 1 || i > (*L).length + 1){return ERROR;/*i值不合法*/}/* 若当前存储空间已满,则增加存储空间 */if((*L).length >= (*L).listsize){newbase = (ElemType*)realloc((*L).elem, ((*L).length + LISTINCREMENT) * sizeof(ElemType));if( !newbase ){/*存储分配失败*/exit(OVERFLOW);}(*L).elem = newbase;/*新的基址*/(*L).listsize += LISTINCREMENT;/*增加的存储容量*/}/* q为插入位置 */q = (*L).elem + i - 1;/*插入位置及以后的元素右移*/for (p = pEnd; p >= q; p-- ){*(p + 1) = *p;}/*插入的元素*/*q = e;++(*L).length;/*表增长1*/return OK;}Status ListDelete(SqList *L, int i, ElemType *e) /* 算法2.5 */{/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) *//* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */ElemType *q = NULL;ElemType *p = NULL;ElemType *pEnd = (*L).elem + (*L).length - 1;/*判断i值是否合法*/if(i < 1 || i >= (*L).length + 1){return ERROR;/*i值不合法*/}q = (*L).elem + i - 1;/* q为删除位置 */*e = *q; /* 被删除元素的值赋给e */--(*L).length;/*表减少1*//*插入位置及以后的元素左移*/for (p = q; p <= pEnd; p++ ){*p = *(p + 1);}return OK;}Status ListTraverse(SqList L,void(*vi)(ElemType*)){/* 初始条件:顺序线性表L已存在 *//* 操作结果:依次对L的每个数据元素调用函数vi()。一旦vi()失败,则操作失败 *//*           vi()的形参加'&',表明可通过调用vi()改变元素的值 */int count = 1;ElemType *p = L.elem;while (count <= L.length){vi(p++);++count;}printf("\n");return OK;}/*判断用辅助函数*/Status comp(ElemType c1,ElemType c2) /* 数据元素判定函数(平方关系) */{if(c1 == c2 * c2){return TRUE;}else{return FALSE;}}/*输出用辅助函数*/void visit(ElemType *c) /* ListTraverse()调用的函数(类型要一致) */{printf("%d ",*c);}/*辅助函数*/void dbl(ElemType *c) /* ListTraverse()调用的另一函数(元素值加倍) */{*c *= 2;}/*辅助函数*/Status equal(ElemType c1, ElemType c2){ /* 判断是否相等的函数,Union()用到 */if(c1 == c2){return TRUE;}else{return FALSE;}}/* 算法2.1假设线性表LA和LB分别表示两个集合A和B,现要求新的e集合A=AUB,这就要求扩大线性表LA,将存在于线性表LB中而不存在于线性表LA中的元素插入到线性表LA中进行查访,若不存在则插入之。该算法的时间复杂度:O(La.length×Lb.length)*/void Union(SqList *La,SqList Lb){ /* 将所有在线性表Lb中但不在La中的数据元素插入到La中 */int i;ElemType* e = NULL;int La_Len = ListLength(La);int Lb_Len = ListLength(&Lb);for (i = 0; i <= Lb_Len; i++){GetElem(Lb,i,e);/* 取Lb中第i个数据元素赋给e *//* La中不存在和e相同的元素,则插入之 */if (!LocateElem(*La, *e, equal)){ ListInsert(La, ++La_Len, *e);}}}//Union/* 算法2.2已知线性表LA和LB中的数据元素按值非递减有序排列,县要求将LA和LB归并为一个新的线性表LC,且LC中的数据元素任按值递减有序排列。该算法的时间复杂度:O(La.length + Lb.length)*/void MergeList(SqList La,SqList Lb,SqList *Lc) /* 算法2.2 */{/* 已知线性表La和Lb中的数据元素按值非递减排列。 *//* 归并La和Lb得到新的线性表Lc,Lc的数据元素也按值非递减排列 */int La_Len = ListLength(&La);int Lb_Len = ListLength(&Lb);int posC = 1;int posA = 1;int posB = 1;ElemType* e1 = NULL;ElemType* e2 = NULL;InitList(Lc);/*LA和LB均非空*/while(posA < La_Len && posB < Lb_Len){GetElem(La, posA, e1);GetElem(Lb, posB, e2);if (e1 >= e2){ListInsert(Lc, posC++, *e2);posB++;}else{ListInsert(Lc, posC++, *e1);posA++;}}while (posA <= La_Len){GetElem(La, posA++, e1);ListInsert(Lc, posC++, *e1);}while (posB <= Lb_Len){GetElem(Lb, posB++, e2);ListInsert(Lc, posC++, *e2);}}//MergeListint _tmain(int argc, _TCHAR* argv[]){SqList L;ElemType e,e0;Status i;int j,k;i=InitList(&L);printf("初始化L后:L.elem=%u L.length=%d L.listsize=%d\n",L.elem,L.length,L.listsize);for(j=1;j<=5;j++){i=ListInsert(&L,1,j);}printf("在L的表头依次插入1~5后:*L.elem=");for(j=1;j<=5;j++){printf("%d ",*(L.elem+j-1));}printf("\n");printf("L.elem=%u L.length=%d L.listsize=%d\n",L.elem,L.length,L.listsize);i=ListEmpty(L);printf("L是否空:i=%d(1:是 0:否)\n",i);i=ClearList(&L);printf("清空L后:L.elem=%u L.length=%d L.listsize=%d\n",L.elem,L.length,L.listsize);i=ListEmpty(L);printf("L是否空:i=%d(1:是 0:否)\n",i);for(j=1;j<=10;j++){ListInsert(&L,j,j);}printf("在L的表尾依次插入1~10后:*L.elem=");for(j=1;j<=10;j++){printf("%d ",*(L.elem+j-1));}printf("\n");printf("L.elem=%u L.length=%d L.listsize=%d\n",L.elem,L.length,L.listsize);ListInsert(&L,1,0);printf("在L的表头插入0后:*L.elem=");for(j=1;j<=ListLength(&L);j++){ /* ListLength(L)为元素个数 */printf("%d ",*(L.elem+j-1));}printf("\n");printf("L.elem=%u(有可能改变) L.length=%d(改变) L.listsize=%d(改变)\n",L.elem,L.length,L.listsize);GetElem(L,5,&e);printf("第5个元素的值为:%d\n",e);for(j=3;j<=4;j++){k=LocateElem(L,j,comp);}if(k){printf("第%d个元素的值为%d的平方\n",k,j);}else{printf("没有值为%d的平方的元素\n",j);}   for(j = 1;j <= 2;j++) /* 测试头两个数据 */   {     GetElem(L, j, &e0); /* 把第j个数据赋给e0 */     i=PriorElem(L, e0, &e); /* 求e0的前驱 */     if(i == INFEASIBLE)       printf("元素%d无前驱\n",e0);     else       printf("元素%d的前驱为:%d\n",e0,e);   }for(j=ListLength(&L)-1;j<=ListLength(&L);j++) /* 最后两个数据 */{GetElem(L,j,&e0); /* 把第j个数据赋给e0 */i=NextElem(L,e0,&e); /* 求e0的后继 */if(i==INFEASIBLE){printf("元素%d无后继\n",e0);}else{printf("元素%d的后继为:%d\n",e0,e);}}k=ListLength(&L); /* k为表长 */for(j=k+1;j>=k;j--){i=ListDelete(&L,j,&e); /* 删除第j个数据 */if(i==ERROR){printf("删除第%d个数据失败\n",j);}else{printf("删除的元素值为:%d\n",e);}}printf("依次输出L的元素:");ListTraverse(L,visit); /* 依次对元素调用visit(),输出元素的值 */printf("L的元素值加倍后:");ListTraverse(L,dbl); /* 依次对元素调用dbl(),元素值乘2 */ListTraverse(L,visit);DestroyList(&L);printf("销毁L后:L.elem=%u L.length=%d L.listsize=%d\n",L.elem,L.length,L.listsize);return 0;}
原创粉丝点击