一、线性表之顺序表

一、线性表之顺序表

1.1顺序表的定义

​ 线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。又称顺序表。

顺序表的存储

1.2顺序表的特点

1)逻辑上相邻的元素 ai, ai+1, 其存储位置也是相邻的;
2)对数据元素ai的存取为随机存取或按地址存取。
3)存储密度高。 存储密度D=(数据结构中元素所占存储空间)/( 整个数据结构所占空间) 。

2.1顺序表的存储类型

2.1.1 静态分配
#define MAXSIZE 100 
typedef int ElemType;
//静态分配的顺序表
typedef struct {
	ElemType data[MAXSIZE];		//存放元素
	int len;					//顺序表的长度
}SqList;		//声明顺序表的类型
2.1.2 动态分配
#define LIST_INIT_SIZE 100		//存储空间的初始化分配量
#define LISTINCREMENT 10		//分配增量
typedef int ElemType;
//动态分配的顺序表
typedef struct
{
	ElemType* elem;		//存储区域的基址
	int len;			//当前表的长度
	int size;			//当前以分配的存储容量
}SqList;			//顺序表类型

3.1 对顺序表的基本操作

3.1.1初始化顺序表
void InitList(SqList& L);
{
	L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
	if (!L.elem)
		exit(-1);	//内存分配失败
	L.len = 0;
	L.size = LIST_INIT_SIZE;
	return 1;
}
3.1.2 查找顺序表中第i个位置的元素的值
ElemType GetElem(SqList L, int i)
{
	ElemType e;
	e = L.elem[i];
	return e;
}
3.1.3查找顺序表中第一个值等于e的元素,并返回其下标
int LocateElem(SqList L, ElemType e)
{
	if (L.len == 0)
		return 0;
	int i;
	for (i = 0; i < L.len; i++)
	{
		if (L.elem[i] == e)
			return i + 1;
	}
}
3.1.4在顺序表L的第i个位置(1<=i<=L.len+1)前插入新元素e
//在顺序表L的第i个位置(1<=i<=L.len+1)前插入新元素e
Status SqListInsert(SqList& L, int i, ElemType e)
{
	if (i<1 || i>L.len)
		return -1;
	SqListCapacity(L);	//判断内存是否足够,如果不足就进行扩容
	int j;
	for (j = L.len; j > i; j--)
	{
		L.elem[j] = L.elem[j - 1];		//从i元素开始整体右移一个元素
	}
	L.elem[i - 1] = e;		
	L.len++;		//长度加一
	return 1;
}
3.1.5删除第i个位置的元素,并返回第i个位置的值
//删除顺序表L中的第i个位置(1<=i<=L.len)的元素e,并返回e的值
Status DelSqList(SqList& L, int i, ElemType& e)
{
	if (i<1 || i>L.len)		//判断是否越界
		return -1;
	e = L.elem[i - 1];	//存放第i个元素的值
	int j;
	for (j = i; j < L.len; j++)
	{
		L.elem[j - 1] = L.elem[j];		//第i个元素之后的元素整体前移一个元素
	}
	L.len--;	//长度减一
	return 1;
}

4.1顺序表的图形解释

顺序表的基本操作顺序表的基本操作

二、对顺序表习题的练习

顺序表A和顺序表B这两个线性表元素个数分别为m、n,若表中数据都是递增有序的,且这m+n个元素中没有重复,对下面问题进行求解。

1、设计一个算法将这两个顺序表归并到另顺序表C中,且C中元素仍是递增有序的

解题思路:

​ 采用有序表的二路归并思路,用 i 和 j 分别遍历A和B,比较它们的当前元素,将较小的复制到顺序表C中,当A或B中有一个遍历结束后,再将另一个顺序表余下的元素全部复制到顺序表C中,算法如下:

void test1(SqList A, SqList B, SqList& C)
{
	int i = 0, j = 0, k = 0;
	while (i < A.len && j < B.len)	//有序顺序表A和B都没有遍历完时
	{
		if (A.elem[i] < B.elem[j])	//归并较小的元素A.elem[i]
		{
			C.elem[k] = A.elem[i];
			i++;
			k++;
		}
		else		//归并较小的元素B.elem[j]
		{
			C.elem[k] = B.elem[j];
			j++;
			k++;
		}
	}
	while (i < A.len)	//有序顺序表A没有遍历完时
	{
		C.elem[k] = A.elem[i];
		i++;
		k++;
	}
	while (j < B.len)		//有序顺序表B没有遍历完时
	{
		C.elem[k] = B.elem[j];
		j++;
		k++;
	}
	C.len = k;	//设置C的长度
}

​ 本题时间复杂度为O(m+n),空间复杂度O(1)

2、如果顺序表B的大小为m+n个单元,是否可以不利用顺序表C而将结果存放与顺序表B中实现合并?

解题思路:

​ 可以采用有序表的二路归并思路,用 i 从后向前遍历顺序表A,用 j 从后向前遍历顺序表B,将较大元素插入B的尾部,算法如下:

void test2(SqList A, SqList& B)
{
	int i = A.len - 1, j = B.len - 1, k = A.len + B.len - 1;
	while (i >= 0 && j >= 0)
	{
		if (A.elem[i] > B.elem[j])		//将较大的元素A.elem[i]放到B的尾部
		{
			B.elem[k] = A.elem[i];
			i--;
			k--;
		}
		else		//将较大的元素B.elem[i]放到B的尾部
		{
			B.elem[k] = B.elem[j];
			j--;
			k--;
		}
	}
	while (i >= 0)			//A没有遍历结束
	{
		B.elem[k] = A.elem[i];
		i--; k--;
	}
	while (j>= 0)		//B没有遍历结束
	{
		B.elem[k] = B.elem[j];
		j--; k--;
	}
	B.len += A.len;		//修改B的长度
}

​ 本题时间复杂度为O(m+n),空间复杂度O(1)

3、设顺序表A中前m个元素递增有序,后n个元素也递增有序,设计一个算法,使得整个顺序表依然有序,要求空间复杂度为O(1)

解题思路:

​ 本题因为要求空间复杂度为O(1),因此算法中不能新建顺序表,算法思路是将顺序表A的后半部分插入前半部分中,使得整个表有序,其长度不变,算法如下:

void test3(SqList& A, int m, int n)
{
	int i = 0, j = m, k;		//j遍历后半部分的有序表,同时记录前半部分有序表的长度
	ElemType temp;
	while (j < A.len && i < j)
	{
		if (A.elem[j] > A.elem[j - 1])		//整个表一递增有序,推出循环
			break;
		else if(A.elem[j]<A.elem[i])		//将A.elem[j]插入前半部分中
		{
			temp = A.elem[j];
			for (k = j - 1; k >= i; k--)	//将A.elem[i]及之后的元素后移
			{
				A.elem[k + 1] = A.elem[k];
			}
			A.elem[i] = temp;	//将A.elem[j]插入A.elem[i]处
			i++;
			j++;
		}
		else
		{
			i++;
		}
	}
}

​ 本题时间复杂度为O(m*n),空间复杂度O(1)

4、对于第3题算法,在对空间复杂度没有限制的条件下,能否设计具有同样功能的算法时间复杂度为O(m+n)呢?

解题思路:

​ 在算法中建立一个临时顺序表B,先将A的后半部分元素复制到B中,这样A看成只有m个元素的有序表,采用第二题的算法思路将A,B两个顺序表归并为顺序表A ,算法如下:

void test4(SqList& A, int m, int n)
{
	SqList B;	//建立临时顺序表B
	int i, j, k;
	for (i = m, j = 0; j < m + n; i++, j++)		//将A的后半部分复制到B中
	{
		B.elem[j] = A.elem[i];
	}
	i = m - 1;
	j = n - 1;
	k = m + n - 1;
	while (i >= 0 && j >= 0)		//将A,B归并到A中
	{
		if (A.elem[i] > B.elem[j])		//归并较大元素 B.elem[j];
		{
			A.elem[k] = A.elem[i];
			i--;
			k--;
		}
		else		//归并较大元素 B.elem[j];
		{
			A.elem[k] = B.elem[j];
			j--;
			k--;
		}
	}
	while (i >= 0)			//A没有遍历时
	{
		A.elem[k] = A.elem[i];
		i--;
		k--;
	}
	while (j >= 0)		//B没有遍历时
	{
		A.elem[k] = B.elem[j];	
		j--;
		k--;
	}

}

本题时间复杂度为O(m+n),空间复杂度O(n)(算法中临时顺序表B的空间大小为n)

三、总结

优点:

1) 可以方便地随机存取表中任一结点。

2)无须增加额外的存储空间表示结点间的逻辑关系。

缺点

1)插入和删除运算不方便,通常须移动大量结点,效率较低。

2)难以进行连续的存储空间的预分配,尤其是当表变化较大时。

3)当你使用静态分配空间时,不知道提前开辟多大的空间合适,#define SIZE X 过大过小都不合适。

.elem[k] = B.elem[j];
j–;
k–;
}

}


本题时间复杂度为O(m+n),空间复杂度O(n)(算法中临时顺序表B的空间大小为n)

# 三、总结

### 优点:

1) 可以方便地随机存取表中任一结点。 

2)无须增加额外的存储空间表示结点间的逻辑关系。

### 缺点

1)插入和删除运算不方便,通常须移动大量结点,效率较低。

2)难以进行连续的存储空间的预分配,尤其是当表变化较大时。  

3)当你使用静态分配空间时,不知道提前开辟多大的空间合适,#define   SIZE   X  过大过小都不合适。





















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值