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)了,不再占用篇幅粘贴在这里了。