【数据结构】二、线性表(顺序表)

目录

一、线性结构

二、线性表

三、顺序表

顺序表实现-静态数组

顺序表实现-动态数组

练习题

1.合并数组

2.划分问题

3.连续插入

4.连续删除


一、线性结构

定义:结构是非空有限集,有且仅有一个开始节点和结束节点所有节点最多只有一个直接前驱和直接后继。节点间逻辑关系:(1:1)

线性结构的逻辑类型:包括线性表、堆栈、队列、字符串、数组等。最典型、最常用的是线性表。(线性结构不是线性表)

二、线性表

定义:有限数据元素形成的序列

【数据结构】二、线性表(顺序表)_第1张图片 线性表的结构

特点:数据元素都为同类型。元素间关系为线性。

线性表的物理结构类型顺序存储结构和链式存储结构

ps:有序表:所有元素以递增或递减方式有序排列的线性表。有序表是线性表的一部分。有序表(数值上有序)不等于顺序表(物理上有序)。

三、顺序表

顺序存储特点

  1. 逻辑上相邻的元素,物理上也相邻
  2. 存储密度大(存储密度 = 数据元素的值所需的存储空间 / 数据元素实际所需的存储空间)
  3. 若已知表中首元素在存储器中的位置,则其他元素存放位置亦可求出(利用数组a[n]的下标)
  4. 便于随机存取
  5. 不便于插入删除

优点:可以随机存取表中任一元素,方便快捷

缺点:在插入或删除某一元素时,需要移动大量元素

顺序表元素地址计算:LOC(ai)  = 首地址 + 每个元素的存储空间 *(i - 1)

顺序表在C语言中用一维数组来描述。

顺序表实现-静态数组

操作

名称 修改 插入 删除
目的 修改第pos个元素的值 在线性表第pos个位置前插入一个元素 删除线性表的第pos个位置上的元素
步骤 l.elem[pos-1]=value

将第n至第pos位的元素向后移动一个位置;

将要插入的元素写到第pos个位置;

表长加1。

将第pos+1至第n 位的元素向前移动一个位置;

表长减1。

时间复杂度 O(1) 平均时间复杂度O(n) 平均时间复杂度O(n)
注意 pos都是从1开始算的               判断pos值是否合法,表是否已满

判断pos是否合法,表是否为空

插入删除的平均空间复杂度为O(1)

代码

说明:

  1. 函数形参加”&“表示引用。如 initlist(list& l),l 虽然不是全局变量,但通过引用可以在函数中改变 l 的相关值,与传指针效果相同。
  2. 函数应具有健壮性,输入数字不在范围内或表空、表满要输出相应报错说明,而不是让程序崩溃。
//线性表的静态顺序存储(数组)
#include
#include

#define MAXSIZE 20  //最多放置数据个数

typedef int elemtype;  //数据类型

typedef struct {
	elemtype elem[MAXSIZE];
	int length;
}list;

void insert(list& l, int pos, elemtype value) //在第pos个元素前插入元素
{
	int i;
	if (l.length == MAXSIZE)
	{
		printf("full!");
		return;
	}

	if (pos<1 || l.length + 1= pos - 1; i--)
			l.elem[i + 1] = l.elem[i];

	l.elem[pos - 1] = value;
	l.length++;
}


elemtype delet(list& l, int pos, elemtype& e)//删除第i个元素,e返回其值 
{
	int i;
	if (l.length == 0 || pos<1 || pos>l.length)
	{
		printf("wrong!");
		return NULL;
	}

	e = l.elem[pos - 1];

	if (pos < l.length)  //如果不是删除最后值,pos及以后元素前移
		for (i = pos; i < l.length; i++)
			l.elem[i - 1] = l.elem[i];

	l.length--;
	return e;
}


void changeelem(list& l, int pos, elemtype value)  //改变元素值
{
	l.elem[pos - 1] = value;
}

void output(list L) //打印线性表中所有元素
{
	printf("当前顺序表的长度为: %d\n", L.length);
	for (int i = 0; i < L.length; i++) {
		printf("%d ", L.elem[i]);
	}
	printf("\n");
}

int main() {
	list l;
	l.length = 0;

	for (int i = 1; i <= 10; i++) {
		insert(l, i, i);
	}
	output(l);

	insert(l, 3, 99);
	output(l);
	
	elemtype e;
	delet(l, 6, e);
	output(l);
	printf("%d\n", e);
	
	e = 99;
	changeelem(l, 7, e);
	output(l);
}

顺序表实现-动态数组

操作

名称 初始化 插入 删除 定位
目的 为数组开辟空间 在第pos个元素之前插入一个值为value的元素 将第pos个位置上的元素删除 根据值找到元素的位置
步骤 申请空间,确定当前表的元素数和存储容量

检测位置是否合法、空间是否足够,不够新增空间、修正存储容量;

元素后移,插入新元素;

修正表长。

检测位置是否合法,元素前移,修正表长 逐个比较,返回下标

采用realloc(p,newsize)扩大空间

注意:newsize是空间的大小,是数据个数*sizeof(数据类型)

时间复杂度       

O( ListLength(L) )

代码: 

#include
#include

#define list_size 3    //最多放置数据个数
#define increment_size 5  //补充空间

typedef int elemtype;

typedef struct {
	elemtype* elem;
	int length;
	int listsize;
}list;

void initlist(list& l) {   //构造一个新的线性表
	l.elem = (elemtype*)malloc(list_size * sizeof(elemtype));
	if (!l.elem)
	{
		printf("wrong!");
		return;
	}
	
	l.length = 0;
	l.listsize = list_size;
}

void insert(list& l, int pos, elemtype value)  //在第pos个元素前插入元素。注意,长度和pos都是从1开始数,而表从0开始编号
{
	int i;
	if (l.length == list_size) {
		l.elem = (elemtype*)realloc(l.elem, (list_size + increment_size) * sizeof(int));   //realloc(原指针,需要的长度)
		l.listsize += increment_size;
	}

	if (pos<1 || pos>l.length + 1)
	{
		printf("worng number!");
		return;
	}

	if (pos <= l.length) {
		for (i = l.length - 1; i >= pos - 1; i--) {
			l.elem[i + 1] = l.elem[i];
		}
	}
	l.elem[pos - 1] = value;
	l.length++;
}


void delet(list& l, int pos)//删除第i个元素
{
	int i;
	if (l.length == 0 || pos<1 || pos>l.length)
	{
		printf("worng number!\n");
		return;
	}

	printf("\n删除第%d个元素\n",pos);
	if (pos < l.length)
		for (i = pos; i < l.length; i++)
			l.elem[i - 1] = l.elem[i];
	
	l.length--;
}


int locateelem(list l, elemtype value, int& e)   //找到特定值的位置
{
	if (l.length == 0)
	{
		printf("worng number!");
		return 0;
	}
	
	for (e = 0; e < l.length; e++)
		if (l.elem[e] == value)
			break;

	if (e < l.length) 
	{
		printf("\n值为%d的元素为第%d个\n", value, e + 1);
		return ++e;
	}
		
	else {
		printf("not found");
		return 0;
	}
}

void output(list L) //打印线性表
{
	printf("当前顺序表的长度为: %d\n", L.length);
	for (int i = 0; i < L.length; i++) {
		printf("%d ", L.elem[i]);
	}
	printf("\n");
}

int main() {
	list l;
	initlist(l);
	output(l);

	int i = 0;
	for (i = 1; i <= list_size; i++)
		insert(l, i, i);
	output(l);

	insert(l, 3, 99);
	output(l);

	delet(l, 2);
	output(l);

	int e;
	locateelem(l, 99, e);
}

练习题

1.合并数组

有两个有序的顺序表LA(有m个元素)和LB(有n个元素)其元素均以从小到大的升序排列,编写一个函数将它们合并成一个顺序表LC,并要求LC仍保持其有序性。

#include
#include

#define elemtype int

typedef struct {
	elemtype* elem;
	int length;
}list;

void initlist(list& l, int num) //构造一个新的线性表
{   
	l.elem = (elemtype*)malloc(num * sizeof(elemtype));
	if (!l.elem)
	{
		printf("wrong!");
		return;
	}
	l.length = 0;
}

void insert(list& l, int pos, elemtype value)
{
	int i;

	if (pos<1 || pos>l.length + 1)
	{
		printf("worng number!");
		return;
	}

	if (pos <= l.length) {
		for (i = l.length - 1; i >= pos - 1; i--) {
			l.elem[i + 1] = l.elem[i];
		}
	}
	l.elem[pos - 1] = value;
	l.length++;
}

void output(list L) //打印线性表
{
	for (int i = 0; i < L.length; i++) {
		printf("%d ", L.elem[i]);
	}
	printf("\n");
}

void function(list la, list lb, list lc)
{
	int a = 0, b = 0, c = 0;
	while (a < la.length && b < lb.length)
	{
		if (la.elem[a] <= lb.elem[b])
			lc.elem[c++] = la.elem[a++];
		else
			lc.elem[c++] = lb.elem[b++];
	}

	if (a = la.length)
		while(b < lb.length)
			lc.elem[c++] = lb.elem[b++];

	if (b = lb.length)
		while (a < la.length)
			lc.elem[c++] = la.elem[a++];

	printf("LC为:");
	for (int i = 0; i < la.length + lb.length; i++)
		printf("%d ", lc.elem[i]);

}

int main() {
	int i, temp, numa, numb;
	list la,lb,lc;

	printf("la长度:");
	scanf_s("%d", &numa);
	initlist(la, numa);
	
	printf("输入元素,空格间隔:");
	for (i = 1; i <= numa; i++) {
		scanf_s("%d", &temp);
		insert(la, i, temp);
	}

	printf("lb长度:");
	scanf_s("%d", &numb);
	initlist(lb, numb);

	printf("输入元素,空格间隔:");
	for (i = 1; i <= numb; i++) {
		scanf_s("%d", &temp);
		insert(lb, i, temp);
	}
	
	printf("LA为:");
	output(la);
	printf("LB为:");
	output(lb);

	initlist(lc, numa+numb);
	function(la, lb, lc);


}

2.划分问题

将动态顺序表 (a1,a2,... ,an) 重新排列为以 a1 为界的两部分:a1  前面的值均比 a1小,a1 后面的值都比 a1 大。这一操作称为划分。a1称为基准。

采用了快速排序思想:指针pl、pr分别指向数组两端。pr先向左移动,找到比基准小的值赋给pl,pl再向右移动,找到比基准大的值赋给pr,直到两指针相遇,将基准放在相遇处。 

//采用一趟快速排序思想,以a1作为枢轴元素,分别从高到低和从低到高扫描元素
#include 
#include 

void function(int*& l, int num)
{
	int target = l[0];
	int pl = 0, pr = num - 1;
	while (pl < pr) 
	{
		while (pl < pr && l[pr] > target)
			pr--;

		if (pl < pr)
			l[pl++] = l[pr];

		while (pl < pr && l[pl] < target)
			pl++;

		if (pl < pr)
			l[pr--] = l[pl];
	}
	l[pl] = target;
}

int main() {

	int num, i;
	printf("元素个数:");
	scanf_s("%d", &num);

	int* l = (int*)malloc(num * sizeof(int));
	if (!l)  return 0;

	printf("输入内容:");
	for (i = 0; i < num; i++)
		scanf_s("%d", &l[i]);
	
	function(l, num);

	printf("更新后: ");
	for (i = 0; i < num; i++)
		printf("%d ", l[i]);
}

3.连续插入

在具有n个元素的动态顺序表中第i个位置之后插入m个元素

用realloc扩大空间,后移旧元素,放入新元素

大二上学期学习数据结构,这是一段艰辛但收获颇丰的旅程。期末临近,特将日常笔记及代码整理成文,当作复习,也希望能给各位计算机学习者提供帮助。如有错误,请留言指正。2023.12.5

你可能感兴趣的:(数据结构,数据结构,算法,开发语言)