数据结构(一)——线性表的顺序存储原理及实现

一、线性表介绍

1、定义:由n(n>0)个相同类型的元素组成的有序集合,如图

这里所说的线性表是逻辑结构,表示元素一对一的相邻关系,是独立于存储结构(顺序表和链表)的,他们属于不同层面的概念

2、特点:

  • ➢表中元素的个数是有限的。
  • ➢表中元素的数据类型都相同。意味着每一个元素占用相同大小的空间
  • ➢表中元素具有逻辑上的顺序性,在序列中各元素排序有其先后顺序

3、实现方式——顺序表、链表

3.1顺序表:线性表的顺序表示

逻辑上相邻的两个元素在物理位置上也相邻

以上代码描述:使用结构体定义, 数组一开始要定义好大小60,访问时通过下标,注意数组的长度和线性表的长度不一样

3.2优缺点:

优点:

  • ➢可以随机存取(根据表头元素地址和元素序号)表中任意一个元素。
  • ➢存储密度高,每个结点只存储数据元素。

缺点:

  • ➢插入和删除操作需要移动大量元素。
  • ➢线性表变化较大时,难以确定存储空间的容量。
  • ➢存储分配需要一整段连续的存储空间,不够灵活。

3.3插入操作:7,6,5,4要往后移动一位,才把x插到4的位置

  • 最好情况:在表尾插入元素,不需要移动元素,时间复杂度为O(1)。
  • 最坏情况:在表头插入元素,所有元素依次后移,时间复杂度为O(n)。
  • 平均情况:在插入位置概率均等的情况下,平均移动元素的次数为n/2,时间复杂度O(n)
  • 时间复杂度O(n) 要把系数和一阶项都去掉

伪代码:

这里L就是定义出来的SqList 结构体的缩写

3.4 删除操作:5,6,7前移一位

  •  ➢最好情况:删除表尾元素,不需要移动元素,时间复杂度为O(1)。
  • ➢最坏情况:删除表头元素,之后的所有元素依次前移,时间复杂度为O(n)。
  • ➢平均情况:在删除位置概率均等的情况下,平均移动元素的次数为(n-1)/2,时间复杂度为O(n)。

伪代码:

 注意:插入和删除的时候,变量i的范围是不一样的

3.5动态分配的数组属于顺序存储结构吗?

动态分配:int *p = malloc(sizeof(int )*20),仍然属于顺序存储,物理结构没有变化,还是随机存取的,只是分配的空间可以在运行时决定,访问任意一个元素都可以通过地址 

【随机存取就是通过一个公式可以拿到任意一个元素】

【直接定义数组是在栈空间上的,申请动态分配的数组是在堆空间上,都支持随机存取】

 二、代码

顺序表的增、删、查

#include <stdlib.h>
#include <stdio.h>
#include <iostream.h>

#define MAXSIZE 60
typedef int ElemType;//顺序表中的元素类型
//静态分配
typedef struct  {
	ElemType data[MAXSIZE];//定义的数组,用来存元素
	int length;//当前顺序表中的元素个数
}SqList;
/*插入*/
//参数:顺序表、插入位置、插入的元素
bool ListInsert(SqList &L,int i,ElemType elem)
{
	if (i<1 || i>L.length+1)//判断插入的位置是否合法
	{
		return false;
	}
	if (L.length>MAXSIZE)//超出空间
	{
		return false;
	}
	for (int j=L.length;j>=i;j--)//移动顺序表中的元素
	{
		L.data[j]=L.data[j-1];
		
	}
	L.data[i-1]=elem;//插入第一个位置,访问的下标为0
	L.length++;//顺序表长度+1
	return true;
}
/*删除*/
//参数:顺序表、删除位置、删除的元素(要打印)
//elem使用引用是为了拿出删除元素对应的值
bool ListDelete(SqList &L,int i,ElemType &elem)
{
	if (i<1 || i>L.length)
	{
		return false;
	}
	if (L.length == 0)//顺序表中无元素
	{
		return false;
	}
	elem = L.data[i-1];//删除的第i个元素赋值给elem
	for (int j = i;j<L.length;j++)//元素从后往前移动
	{
		L.data[j-1]=L.data[j];
	}
	L.length--;
	return true;
	
}
/*查找*/
int findElem(SqList &L,ElemType elem)
{
	
	for (int i=0;i<L.length;i++)
	{
		if (L.data[i]==elem)
		{
			return i+1;//+1就是在顺序表中的位置
		}
	}
	return 0;//查找失败
}
/*打印*/
void PrintList(SqList &L)
{
	for (int i=0;i<L.length;i++)
	{
		
		cout<<L.data[i]<<endl;
	}
}

int main()
{
	SqList L;//顺序表名称
	bool res;//查看返回值
	ElemType pdel;//存要删除的元素
	//先在顺序表中赋值
	L.data[0]=6;
	L.data[1]=3;
	L.data[2]=8;
	L.length = 3;
	cout<<"**********************插入操作**********************"<<endl;
	res = ListInsert(L,2,99);//第二个位置插入9
	if (res)
	{
		cout<<"插入成功,"<<"插入后的顺序表为"<<endl;
		PrintList(L);
	}
	else
	{
		cout<<"插入失败"<<endl;
	}
	res = ListDelete(L,1,pdel);//删除第一个元素
	if (res)
	{
		cout<<"删除成功,"<<" 删除的元素为"<<pdel<<" 删除后的顺序表为"<<endl;
		PrintList(L);
	}
	else
	{
		cout<<"删除失败"<<endl;
	}
	int ret = findElem(L,99);
	if (ret)
	{
		cout<<"查找成功"<<" 查找的元素位置为"<<res<<endl;
	}
	else
	{
		cout<<"查找失败"<<endl;
	}


	return 0;
}

 上述也可以用动态顺序表实现,结构体中加上动态数组的最大容量,一开始利用malloc申请空间,其他都不变

三、结果

补充:顺序存储和链式存储的优缺点:

猜你喜欢

转载自blog.csdn.net/hml111666/article/details/122848223