您的位置:首页 > 理论基础 > 数据结构算法

数据结构学习笔记 --- 线性表 (顺序表)

2012-02-04 19:24 295 查看
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)了,不再占用篇幅粘贴在这里了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: