1. 引言
据元素,比如说数组。 链式存储结构就是可以用不连续的地址来存储线性表的数据元素。线性表从存储结构上可以分为顺序存储结构和链式存储结构。顺序存储结构:是指用一组连续的存储单元依次存储线性表的数
常见的线性表的基本操作:(12个)
1. InitList(L)
构造一个空的线性表L,即表的初始化。
2. DestroyList(L)
销毁线性表,包括释放其占用的空间、链表长度置为0等
3. ClearList(L)
将线性表L重置为空表
4. ListEmpty(L)
判断线性表是否为空
5. ListLength(L)
求线性表的长度
6. GetElem(L,i,&e)
取线性表L中的第i个结点,这里要求1≤i≤ListLength(L)
7. LocateElem(L,e,(compare*)(,))
返回L中第1个与e满足关系compare()的数据元素的位序
8. PriorElem(L,cur_e,&pre_e)
若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无定义
9. NextElem(L,cur_e,&next_e)
若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无定义
10. ListInsert(L,i,e)
在线性表L的第i个位置上插入一个值为e 的新结点,使得原编号为i,i+1,…,n的结点变为编号为i+1,i+2,…,n+1的结点。这里1≤i≤n+1,而n是原表L的长度。插入后,表L的长度加1。
11. ListDelete(L,i,&e)
删除线性表L的第i个结点,并用e返回其值,使得原编号为i+1,i+2,…,n的结点变成编号为i,i+1,…,n-1的结点。这里1≤i≤n,而n是原表L的长度。删除后表L的长度减1。
12. ListTraverse(L,(*vi)(&))
依次对L的每个数据元素调用函数vi(),vi()的形参加'&',表明可通过调用vi()改变元素的值
常 见的 关于链表的算法和面试题来讲解。
本文从线性表的顺序表示和实现、线性表的链式表示和实现(包括单链表,双向链表,循环链表)、线性表的应用举例和一些
2. 线性表顺序表示和实现
2.1 顺序表的类型定义:
#define LIST_INIT_SIZE 10 // 线性表存储空间的初始分配量 #define LIST_INCREMENT 2 // 线性表存储空间的分配增量 typedef int ElemType; // 线性表的元素类型 typedef struct _Sqlist{ ElemType *elem; // 存储空间基址 int length; // 当前长度 int listsize; // 当前分配的存储容量(以sizeof(ElemType)为单位) }SqList;
2.2 顺序表示的线性表的基本操作
本文不做一一介绍,只介绍几个比较重要的基本操作。
// 初始条件:顺序线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0) // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 // 若这样的数据元素不存在,则返回值为0。 int LocateElem(SqList L, ElemType e, Status(*compare)(ElemType, ElemType)) { ElemType *p = L.elem; // p的初值为第1个元素的存储位置 int i = 1; // i的初值为第1个元素的位序 while (i <= L.length && !compare(*p++, e)) ++i; if (i <= L.length) return i; else return 0; } // 初始条件:顺序线性表L已存在 // 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, // 否则操作失败,pre_e无定义 Status PriorElem(SqList L, ElemType cur_e, ElemType &pre_e) { ElemType *p = L.elem + 1; // p的初值为第2个元素的存储位置 int i = 2; // i的初值为第2个元素的位序 while (i <= L.length && *p != cur_e) { i++; p++; } if (L.length < i) return INFEASIBLE; // 操作失败 else { pre_e = *--p; return OK; } } // 初始条件:顺序线性表L已存在 // 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, // 否则操作失败,next_e无定义 Status NextElem(SqList L, ElemType cur_e, ElemType &next_e) { ElemType *p = L.elem; // p的初值为第1个元素的存储位置 int i = 1; // i的初值为第1个元素的位序 while (i < L.length && *p != cur_e) { i++; p++; } if (i == L.length) return INFEASIBLE; // 操作失败 else { next_e = *++p; return OK; } } // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1 // 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 Status ListInsert(SqList &L, int i, ElemType e) ElemType *newbase, *q, *p; if (i < 1 || i > L.length + 1) // i值不合法 return ERROR; if (L.length >= L.listsize) // 当前存储空间已满,增加分配 { if(!(newbase=(ElemType *)realloc(L.elem,(L.listsize+LIST_INCREMENT)*sizeof(ElemType)))) exit(OVERFLOW); // 存储分配失败 L.elem=newbase; // 新基址 L.listsize+=LIST_INCREMENT; // 增加存储容量 } 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; } // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) // 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 Status ListDelete(SqList &L, int i, ElemType &e) { ElemType *p,*q; if(i < 1 || i > L.length) // i值不合法 return ERROR; 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; }
2.3 两个算法
a. 将所有在线性表Lb中但不在La中的数据元素插入到La中
// 将所有在线性表Lb中但不在La中的数据元素插入到La中
void Union(SqList &La,SqList Lb) // 算法2.1
{
ElemType e;
int La_len, Lb_len;
int i;
La_len = ListLength(La); // 求线性表的长度
Lb_len = ListLength(Lb);
for (i = 1; i <= Lb_len; i++)
{
GetElem(Lb,i,e); // 取Lb中第i个数据元素赋给e
if(!LocateElem(La,e,equal)) // La中不存在和e相同的元素,则插入之
ListInsert(La,++La_len,e);
}
}
b.
已知顺序线性表La和Lb的元素按值非递减排列,归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列。
// 已知顺序线性表La和Lb的元素按值非递减排列。 // 归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列 void MergeList(SqList La,SqList Lb,SqList &Lc) // 算法2.7 { ElemType *pa_last, *pb_last, *pc; ElemType *pa = La.elem; ElemType *pb = Lb.elem; Lc.listsize = Lc.length=La.length+Lb.length; // 不用InitList()创建空表Lc 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) // 表La和表Lb均非空 { // 归并 if(*pa<=*pb) *pc++=*pa++; // 将pa所指单元的值赋给pc所指单元后,pa和pc分别+1(指向下一个单元) else *pc++=*pb++; // 将pb所指单元的值赋给pc所指单元后,pa和pc分别+1(指向下一个单元) } // 以下两个while循环只会有一个被执行 while(pa<=pa_last) // 表La非空且表Lb空 *pc++=*pa++; // 插入La的剩余元素 while(pb<=pb_last) // 表Lb非空且表La空 *pc++=*pb++; // 插入Lb的剩余元素 }
2.4 源程序
顺序表的所有基本操作和2.3中的那两个算法整理在sqlist.cpp中(包含main函数,测试那两个算法和所有的基本操作),放在我的下载资源里(http://download.csdn.net/detail/whz_zb/4227220)了,不再占用篇幅粘贴在这里了。