数据结构二之顺序表增删查找

Posted I am Supreme

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构二之顺序表增删查找相关的知识,希望对你有一定的参考价值。

目录

1、线性表

2、顺序表

3、 接口实现:


正文

1、线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
 

2、顺序表

2.1概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组
上完成数据的增删查改。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储。

//静态顺序表
#define MAXSIZE 100
struct SeqList
{
	int array[MAXSIZE];
	int size;          //顺序表中有效元素的个数
};

2. 动态顺序表:使用动态开辟的数组存储。

typedef int DataType;	//给int其别名为DataType
typedef struct SeqList
{
	DataType * array;//这里不用int的原因:如果后面data是double类型或者其他类型\\
		                 ,只需要在typedef处将int改为需要的类型
	int capacity;   //表示array指向的空间总的大小
	int size;       //表示顺序表中有效元素的个数
}SeqList1;

3、 接口实现:


静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表:

#pragma once
/*为了避免同一个文件被重复包含
方式一:
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__
... ... // 一些声明语句
#endif

方式二:
#pragma once
... ... // 一些声明语句

#ifndef的方式依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,
也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心"撞车",
可能就会导致头文件明明存在,编译器却硬说找不到声明的状况

#pragma once则由编译器提供保证:同一个文件不会被包含多次。
注意这里所说的"同一个文件"是指物理上的一个文件,而不是指内容相同的两个文件。
带来的好处 是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。
对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。
当然,相比宏名碰撞引发的"找不到声明"的问题,重复包含更容易被发现并修正。

方式一由语言支持所以移植性好,方式二 可以避免名字冲突
*/
#if 0
//静态顺序表
#define MAXSIZE 100
struct SeqList
{
	int array[MAXSIZE];
	int size;          //顺序表中有效元素的个数
};
#endif

//动态顺序表
typedef int DataType;	//给int其别名为DataType
typedef struct SeqList
{
	DataType * array;//这里不用int的原因:如果后面data是double类型或者其他类型\\
		                 ,只需要在typedef处将int改为需要的类型
	int capacity;   //表示array指向的空间总的大小
	int size;       //表示顺序表中有效元素的个数
}SeqList1;

//初始化顺序表
void SeqListInit(SeqList1 * ps, int capacity);

//销毁顺序表
void SeqListDestory(SeqList1*ps);

//向顺序表中尾插data;
void SeqListPushBack(SeqList1*ps, DataType data);

// 将顺序表中最后一个元素删除掉
void SeqListPopBack(SeqList1*ps);

// 在顺序表的pos位置插入元素data
void SeqListInsert(SeqList1*ps, int pos, DataType data);

//在顺序表的pos位置删除元素
void SeqListErase(SeqList1*ps, int pos);

//获取有效元素的个数
int SeqListSize(SeqList1* ps);

//获取顺序表的总容量---底层空间总数的大小
int SeqListCapacity(SeqList1*ps);

//检测顺序表是否为空
int SeqListEmpty(SeqList1*ps);

//在顺序表中查找data
int SeqListFind(SeqList1*ps, DataType data);

//将顺序表中的容量扩增到capacity
void SeqListReseave(SeqList1*ps, int capacity);

//测试方法//
//将顺序表中的元素进行打印
void SeqListPrint(SeqList1* ps);
#include"SeqList.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//初始化顺序表
void SeqListInit(SeqList1 * ps, int InitCap)
{
	assert(ps);
	// 1. 申请空间
	ps->array = (DataType *)malloc(InitCap*sizeof(DataType));
	if (NULL == ps->array)
	{
		assert(0);
		return; 
	}
	// 2. 将容量以及有效元素个数设置好
	ps->capacity = InitCap;
	ps->size = 0;
}

//销毁顺序表
void SeqListDestory(SeqList1*ps)
{
	//先判断指针指向的区域是否存在,存在则指针置空,容量以及有效内容为0
	assert(ps);
	if (ps->array)
	{
		ps->array = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}
}

//向顺序表中尾插data;
void SeqListPushBack(SeqList1*ps, DataType data)
{
	//先判断空间是否存在,存在则插入元素
	assert(ps);
	//假设空间足够
	if (ps->size == ps->capacity)
		SeqListReseave(ps, SeqListCapacity(ps) * 2);
	ps->array[ps->size++] = data;

}

// 将顺序表中最后一个元素删除掉
void SeqListPopBack(SeqList1*ps)
{
	if (ps->size==0)
		return;
	ps->size--;
}

//获取有效元素的个数
int SeqListSize(SeqList1* ps)
{
	assert(ps);
	return ps->size;
}

//获取顺序表的总容量---底层空间总数的大小
int SeqListCapacity(SeqList1*ps)
{
	assert(ps);
	return ps->capacity;
}

//检测顺序表是否为空
int SeqListEmpty(SeqList1*ps)
{
	assert(ps);
	if (ps->size == 0)
		return;
}

//在顺序表的pos位置删除元素
void SeqListErase(SeqList1*ps, int pos)
{
	assert(ps);
	if (pos < 0 || pos >= ps->size)
	{
		printf("输入位置超出范围");
		return;
	}
	for (int i = pos + 1; i < ps->size; i++)
	{
		ps->array[i] = ps->array[i + 1];
	}
	ps->size--;

}

//在顺序表中查找data
int SeqListFind(SeqList1*ps, DataType data)
{
	//存在则返回下标,不存在则返回0
	assert(ps);
	for (int i = 0; i < ps->size; ++i)
	{
		if (data == ps->array[i])
			return i;
	}

	return -1;
}

//扩容
void SeqListReseave(SeqList1*ps, int capacity)
{
	assert(ps);
	if (ps->capacity >= capacity)
		return;
	ps->array = (DataType)realloc(ps->array, capacity*sizeof(DataType));
	assert(ps->array);

	ps->capacity *= 2;
}

//在顺序表的pos位置插入元素data
void SeqListInsert(SeqList1*ps, int pos, DataType data)
{
	assert(ps);
	if (pos < 0 || pos >= ps->size)
	{
		printf("输入位置超出范围");
		return;
	}
	//检测空间是否足够
	if (ps->size == ps->capacity)
		SeqListReseave(ps, SeqListCapacity(ps) * 2);
	//插入两种方法,一种i是到搬移到的位置,一种i是搬移的位置
	//i:表示搬移到的位置
	for (int i = ps->size; i < pos; --i)
	{
		ps->array[i - 1] = ps->array[i];
	}
	//i:要搬移的位置
#if 0
	for (int i = ps->size - 1; i <= pos; --i)
	{
		ps->array[i + 1] = ps->array[i];
	}
#endif
	//在pos位置插入
	ps->array[pos] = data;
	ps->size++;
}


/*********测试********/
//将顺序表中的元素进行打印
void SeqListPrint(SeqList1* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; ++i)
	{
		printf("%d" , ps->array[i]);
	}
	printf("\\n");
}
#include<stdio.h>

#include"SeqList.h"

int main()
{
	SeqList1 s;
	SeqListInit(&s, 10);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 5);
	SeqListPushBack(&s, 6);
	SeqListPushBack(&s, 7);
	SeqListPushBack(&s, 8);
	SeqListPushBack(&s, 8);
	SeqListPushBack(&s, 10);
	printf("%d\\n", SeqListCapacity(&s));
	printf("%d\\n", SeqListSize(&s));
	SeqListPrint(&s);

	SeqListInsert(&s, 2, 0);
	SeqListPrint(&s);

	SeqListErase(&s, 2);
	SeqListPrint(&s);

	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	printf("%d\\n", SeqListCapacity(&s));
	printf("%d\\n", SeqListSize(&s));
	SeqListPrint(&s);

	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	printf("%d\\n", SeqListCapacity(&s));
	printf("%d\\n", SeqListSize(&s));
	SeqListPrint(&s);

	SeqListPopBack(&s);
	return 0;

}

 

 

 


 

以上是关于数据结构二之顺序表增删查找的主要内容,如果未能解决你的问题,请参考以下文章

顺序表的增删查改二分查找冒泡和快速排序

数据结构入门顺序表(SeqList)详解(初始化增删查改)

数据结构之顺序表的增删查改等操作详解

数据结构学习笔记(数据结构概念顺序表的增删查改等)详细整理

c++中的顺序表写法,主要实现(增删查改,构造函数,运算符重载)

一学就会的顺序表 —— 结构及各种接口 ( 头插 / 删尾插 / 删特定位置查找 / 插入 / 删除 ) 的实现