数据结构系列之一顺序表

本系列课程主要介绍数据结构的一些知识,其实网上也有很多视频和详细的教程,笔者最近想找一些算法岗位,发现很多公司笔都是考字符串算法操作、数据结构(线性表、栈、队列、图,树)、动态规划、贪心算法、高级数据结构(字典树、线段树)等。

1.1  什么是线性表

       从逻辑上来看,线性表是有n(n>=0)个数据元素组成的有序序列,线性表中元素的个数n(n>=0)定义为线性表的长度,n=0时称为空表。

对于一个非空的线性表,其机构特征如下:

(1)有且仅有一个开始结点,该结点没有直接前驱结点;

(2)有且仅有一个终结结点,该结点没有直接的后续结点;

(3)除(1)(2)外,其余内部结点都有且仅有一个直接前驱结点和一个直接后继结点;

对于同一线性表,各数据元素必须具有相同的数据类型。

1.2  线性表的操作

(1)InitList(L)  初始化操作,建立一个空的线性表;

(2)IsEmpty(L)  判断线性表是否为空,如果线性表为空,则返回true,如果线性表不为空,则返回false;

(3)ClearList(L)  将线性表中所有元素删除;

(4)GetElement(L,i)  返回线性表中下标为i的元素;

(5)LocateElement(L,e)  在线性表中查找指定元素e,若查找成功,返回元素e的下标,若查找不成功,返回-1;

(6)InsertList(L,i,e)  在线性表中下标为i的位置插入元素e;

(7)DeleteList(L,i)  将线性表中下标为i的元素删除;

(8)ListLength(L)  返回线性表中元素个数;

(9)ListTranverse(L,void(*func))  访问线性表中所有元素;

1.3  线性表的顺序存储结构

       顺序存储结构特点:(1)用一段地址连续的存储空间;(2)依次存储线性表中的数据元素。

       数据长度和线性表长度的区别:数据长度是线性表中能保存的数据元素的最多个数,是一个固定值;线性表长度是线性表中已经保存的数据元素的个数,是一个随时变化的值。

       顺序表地址计算方法:L(a(i)) =  L(a(i-1)) + n = L(a(0)) + n*(i-1),其中i,i-1,0代表下标,n表示每个元素所占的字节数。

1.4  代码实现

(1)首先设置MAXSIZE为最大存储的数据长度。

typedef int DataType这一句如果不写的话,我们必须在结构体中指定数据类型,这样写的好处就是如果下次我们想把int修改为double或者float等类型是,我们就不需要去修改结构体里面的定义,只需要修改typedef就可以了。

结构体前面加一个typedef主要是方便后续的调用,如果不加每次定义就要写struct SeqList* L,加上typedef之后,每次定义只写SeqList* L。

#define MAXSIZE 100
typedef int DataType;

typedef struct SeqList
{
	DataType data[MAXSIZE];
	int length;
	
}SeqList;

(2)初始化,初始化只需将length设置为0。

void InitList(SeqList* list){
	list->length = 0;
}

(3)判断线性表是否为空

bool IsEmpty(SeqList* list){
	return list->length == 0;
}

(4)清除线性表

void ClearList(SeqList* list){
	list->length = 0;
}

(5)返回元素个数

int ListLength(SeqList* list){
	return list->length;
}

(6)返回指定元素,是否有人会问这里为什么会返回指针呢?直接返回int类型不行吗?如果这样DataType GetElement(SeqList* list,int i),那么如果查找的下标越界,我们返回什么呢?返回-1,假设原数据中存储的有-1这个值,此时返回的-1是查找正确还是下标越界的返回呢?这里就已经无法区分了,所有这里必须返回DataType*,然后根据指针操作可以取对应的值。

DataType* GetElement(SeqList* list, int i){
	if (i<0 || i>(list->length-1)){
		return NULL;
	}
	return &list->data[i];
}

(7)查找指定元素,如果找到则返回该元素下标,如果没有找到则返回-1。

int LocateElement(SeqList* list , DataType x){
	for (int i = 0; i < (list->length); i++)
	{
		if (list->data[i] == x){
			return i;
		}
	}
	return -1;
}

(8)在指定位置插入一个元素

如果线性表长度已经是MAXSIZE,说明空间已经满,无法插入;

如果插入位置小于0,则插入到开头;如果插入位置大于线性表长度,则插入到数据最后;

每次插入成功,必须将线性表长度+1,这个操作会被忽略掉,一定注意。

bool InsertList(SeqList* list, int i, DataType x){
	
	if (list->length == MAXSIZE)
	{
		return false;
	}
	int pos = 0;
	//开头
	if (i < 0)
	{
		pos = 0;
	}
	//最后
	if (i > list->length-1){
		pos = list->length;
	}
	for (int j = list->length-1; j>=pos; j--)
	{
		list->data[j + 1] = list->data[j];
	}
	list->data[pos] = x;
	list->length++; //插入完成,线性表数据元素+1
	return true;
}

(9)删除一个元素

如果删除的下标不存在,则返回false;

如果找到要删除的下标,把下标后面的所有元素都前移一个位置;

删除成功后,线性表长度-1,这个操作会被忽略掉,一定注意。

bool DeleteList(SeqList* list, int i){
	if (i < 0 || i >= (list->length))
	{
		return false;
	}
	for (int j = i; j < list->length; j++)
	{
		list->data[j] = list->data[j + 1];
	}
	list->length--;
	return true;	
}

(10)合并两个线性表

第一个if判断可能有些问题,这里要分情况讨论,如果只是合并不做相同元素排除的话,两个顺序表的长度之和不能大于最大值,如果相同元素不合并,则需要先判断排除相同元素后,两个表的长度是否大于最大值,这里不是很全,如果用到的同学可以自己补充一下逻辑判断。

void UnionList(SeqList* a, SeqList*b){
	if ((a->length + b->length) > MAXSIZE)
	{
		return;
	}
	for (int i = 0; i < b->length; i++)
	{
		DataType e = b->data[i];
		if (LocateElement(b,e) == -1)
		{
			InsertList(a, a->length, e);
		}
	}
}

(11)顺序表倒置

这里不用过多介绍,找到中间位置,第一个和最后一个交换即可实现。

void reverse(SeqList* list){
	if (list->length<0)
	{
		return;
	}
	for (int i = 0; i < list->length / 2; i++)
	{
		DataType e = list->data[i];
		list->data[i] = list->data[list->length - 1 - i];
		list->data[list->length - 1 - i] = e;
	}
}

(12)顺序表遍历

ListTranverse方法第二个参数是一个函数指针,调用时只需要传递一个函数即可。

void Print(DataType e){
	cout << "e=" << e << endl;
}
void ListTranverse(SeqList* list, void(*printFun)(DataType) ){
	for (int i = 0; i < list->length;i++)
	{
		printFun(list->data[i]);
	}
}

(13)main方法中调用

这里只写了简单的调用,如果有需要可以完善main函数,把所有函数都可以调用一遍。

int main(){
	
	SeqList sl;
	InitList(&sl);
	InsertList(&sl, 0, 10);
	DataType* node = GetElement(&sl, 0);
	cout << "GetElement==" << *node << endl;
	ListTranverse(&sl, Print);
	system("pause");
	return 0;
}

笔者不是写C和C++的,只是学了一些然后开始写小的算法程序,如果有写的不正确的地方还请大神们指点。

最终完整的代码如下:

#include <stdio.h>
#include <iostream>
using namespace std;

#define MAXSIZE 100
typedef int DataType;

typedef struct SeqList
{
	DataType data[MAXSIZE];
	int length;
	
}SeqList;

//初始化线性表
void InitList(SeqList* list){
	list->length = 0;
}

//判断线性表是否为空
bool IsEmpty(SeqList* list){
	return list->length == 0;
}

//清除线性表
void ClearList(SeqList* list){
	list->length = 0;
}

//返回数据元素个数
int ListLength(SeqList* list){
	return list->length;
}

//获取指定元素
DataType* GetElement(SeqList* list, int i){
	if (i<0 || i>(list->length-1)){
		return NULL;
	}
	return &list->data[i];
}
//在线性表中查找指定的元素
int LocateElement(SeqList* list , DataType x){
	for (int i = 0; i < (list->length); i++)
	{
		if (list->data[i] == x){
			return i;
		}
	}
	return -1;
}

//在线性表指定的位置插入一个元素
bool InsertList(SeqList* list, int i, DataType x){
	
	if (list->length == MAXSIZE)
	{
		return false;
	}
	int pos = 0;
	//开头
	if (i < 0)
	{
		pos = 0;
	}
	//最后
	if (i > list->length-1){
		pos = list->length;
	}
	for (int j = list->length-1; j>=pos; j--)
	{
		list->data[j + 1] = list->data[j];
	}
	list->data[pos] = x;
	list->length++; //插入完成,线性表数据元素+1
	return true;
}
bool DeleteList(SeqList* list, int i){
	if (i < 0 || i >= (list->length))
	{
		return false;
	}
	for (int j = i; j < list->length; j++)
	{
		list->data[j] = list->data[j + 1];
	}
	list->length--;
	return true;	
}
//合并两个线性表
void UnionList(SeqList* a, SeqList*b){
	if ((a->length + b->length) > MAXSIZE)
	{
		return;
	}
	for (int i = 0; i < b->length; i++)
	{
		DataType e = b->data[i];
		if (LocateElement(b,e) == -1)
		{
			InsertList(a, a->length, e);
		}
	}
}
//线性表倒置
void reverse(SeqList* list){
	if (list->length<0)
	{
		return;
	}
	for (int i = 0; i < list->length / 2; i++)
	{
		DataType e = list->data[i];
		list->data[i] = list->data[list->length - 1 - i];
		list->data[list->length - 1 - i] = e;
	}
}

//线性表的遍历
void Print(DataType e){
	cout << "e=" << e << endl;
}
void ListTranverse(SeqList* list, void(*printFun)(DataType) ){
	for (int i = 0; i < list->length;i++)
	{
		printFun(list->data[i]);
	}
}

int main(){
	
	SeqList sl;
	InitList(&sl);
	InsertList(&sl, 0, 10);
	DataType* elem = GetElement(&sl, 0);
	cout << "GetElement==" << *elem << endl;
	ListTranverse(&sl, Print);
	system("pause");
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值