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

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







你可能感兴趣的:(数据结构)