从0开始的(c语言)数据结构学习 1:线性表-顺序表

注:本文以造轮子为主,属于相对理论性、教学性的东西

理解:什么是顺序表?

本质上,就是火车。火车的每一节直接连接到下一节,然后每一节火车车厢里,存储着它的货物(数据)。它有着一个车头(基地址),车头后车厢的长度(也就是整个顺序表的长度)。

对于这辆火车(顺序表),我们要有几个基本的功能:

  1. 初始化(创造一辆火车)
  2. 取值(找到第i号车厢存储的数据)
  3. 查找(我们输入一个e,从前往后找到第一个和我们输入的e值相同的车厢)
  4. 插入(在第i节车厢的位置加入一个新的车厢,存入我们输入的数据e)
  5. 删除(把第i节车厢炸了,之后的车厢连接上前面的车厢)

当然除此之外还有很多方法,这里仅介绍以上五种。

————————————分割————————————

具体代码:

注:本代码没有包含main函数(我在其中加入了一些很具体的注释来帮助理解,如果喜欢读代码的朋友可以直接看)
注2:如果你不想纯粹读代码,该代码所有的具体解释请下移

//数据结构-c语言-线性表-顺序表
#include
#include
#include
#include

using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2

typedef int Status;
typedef int ElemType;

#define MAXSIZE 100	

struct player
{
     
	int id;
	string name;
	char pow,def,spe,nok;
};

typedef struct
{
     
	player *elem;//基地址 
	int length;//长度 
}Sqlist;


Status InitList_Sq(Sqlist &L)//【顺序表初始化】目的是创造一个空的线性表L 
//创建一个空表L,此处&L表示形参与实参绑定,对形参的操作可以等价到实参上 
//这里使用的是sqlist,而并非player 
{
     
	L.elem = new player[MAXSIZE];
	//为L的基地址,也就是第一个player后,分配大小为MAXSIZE的数组空间
	//L.elem指向player,new创造了一个长度为100的player数组,并为其分配空间 
	
	
	if(!L.elem)exit(OVERFLOW);
	//!L.elem 非运算符,当L.elem创造失败时,返回1,则视作分配失败,返回OVERFLOW 
	//exit函数,表示在main函数之外强制结束程序 
	//此部分是为了如果产生错误,及时退出避免更多错误 
	
	
	L.length =0;
	//如果分配内存成功,则设定该顺序表目前长度为0 
	return OK;
	//返回成功 
}

Status GetElem(Sqlist L,int i,palyer &pl)//【顺序表取值】目的是用pl返回顺序表中的第i个数据 
{
     
	if(i<1 || i>L.length)//此处i代表的是正常认识中的第几个,而不是计算机中的第几个 
		return ERROR;//如果查询i范围超出正常范围,则返回error
		
	
	pl = L.elem[i-1]; 
	//由于i代表的是正常认识中的位数,因此其值储存在L.elem[i-1]中
	//这一步将其内容赋值给形参(由于有&指向地址,所以实际是给予实参pl),以供进一步调用 
	
	return OK;//如果正常执行查询,则返回OK 
	
}

Status LocateElem_Sq(Sqlist L,double e)//【顺序表查询】目的是返回L中第一个值与pl相同的元素位置
{
     
	for(itn i=0;i<L.length;i++)
	{
     
		if(L.elem[i].pow == e)
		{
     
			return i+1;//由于我们查找的返回目标是正常情况下的第i个,而for中循环的是计算机中的第i个,所以使用i+1 
		}
	}
} 

Status ListInsert_Sq(Sqlist &L,int i,player pl)
{
     
	if(i<1 || (i>L.length + 1))
	{
     
		return ERROR;
		//这里最大区域修改为了length+1,原因是本操作的目的是插入,我们同样可以插入到 length之后一位 
	}
	
	if(L.length == MAXSIZE)
	{
     
		return ERROR;
		//如果目前长度等于我们设定的最大长度,代表它已经满了,不能再插入了,所以失败 
	} 
	
	for(int j=L.length-1;j>=i;j--)
	{
     
		L.elem[j+1]=L.elem[j];//从最后一位开始往前移,每次移一位,从j+1位移到j位 
	}
	L.elem[i-1] =pl;//这里的i依然是我们正常认识时的i,而不是计算机中的i
	++L.length;//表长增加
	return OK; 
} 

Status ListDelete_Sq(SqList &L, int i)//【顺序表的删除】在顺序表中删除第i个 
{
     
	//i值的合法范围是1<=i<=L.length
	if ((i < 1) || (i > L.length))
		return ERROR; //如果i处于范围外,则失败。 
	for (int j = i; j <= L.length; j++)
		L.elem[j - 1] = L.elem[j]; //被删除元素之后的元素前移
	--L.length; //表长减1
	return OK;
}

int main()
{
     
	return 0;
} 


对于代码的具体解释

1,前设_宏定义

#define OK 1
#define ERROR 0
#define OVERFLOW -2

typedef int Status;
typedef int ElemType;

#define MAXSIZE 100	

宏定义:define和typedef,由于使用的是c++,我在这里将OK和ERROR宏定义为1和0用于返回结果,同样OVERFLOW用于exit()函数在主函数之外强行结束。(这玩意下面会解释)

typedef:之前使用c的朋友可能不太理解什么意思,其实就是给其后面的类型起一个新的名字,本质上没有区别。比如typedef int Status;,就是指,给int起一个新名字叫Status,之后使用的时候,如果遇到Status,它本质上仍然是int

2,前设_结构

struct player
{
     
	int id;
	string name;
	char pow,def,spe,nok;
};

typedef struct
{
     
	player *elem;//基地址 
	int length;//长度 
}Sqlist;

这里我们写一个结构叫做player,它包含id,name和四个属性。当然这并不重要,你无论如何称呼这个结构,给它设内容都不会有任何关系。重点在于下面的我们称作Sqlist的结构。

就像上面我们说的火车头,其实就是这个Sqlist了,它储存着顺序表的基地址(火车头的位置)和长度。

3,函数_初始化顺序表

Status InitList_Sq(Sqlist &L)
{
     
	L.elem = new player[MAXSIZE];
	if(!L.elem)exit(OVERFLOW);
	L.length =0;
	return OK;
}
【作用解释】

你们可能会在主函数这样来创造一个Sqlist:

SqList L;

但我们发现一个问题,就是这样创建完之后,它并不能使用。为什么?因为你并咩有给它分配任何一点内存,它就相当于只是一个火车头的图纸,我们虽然有图纸,但是火车还不存在。

因此,我们的第一步,是将这个图纸,变成火车

思路:
  1. 分配内存,让火车从图纸变成具体存在的火车
    L.elem = new player[MAXSIZE];长度为100个player的长度(结构体的长度不会请先学习结构体)
  2. 如果分配内存失败,结束程序(防止火车跑着跑着因为莫名其妙的原因炸了)
    if(!L.elem)exit(OVERFLOW);
  3. 告诉火车头:兄dei,你造好了,现在的长度是0
    L.length =0;

如果你是第一次接触数据结构/c++语言,可能会不知道exit();函数,我在这里做一个简单的解释:

exit();函数通常用于在主函数之外直接停止程序。(通常我们在主函数中会使用return;)。它通常有两种参数:

exit(0);//正常退出
exit(1);//非正常退出

不过事实上,参数除了0以外,都是非正常退出,比如exit(10086)或者本文的exit(-2)exit(OVERFLOW))。

4,函数_取值

Status GetElem(Sqlist L,int i,palyer &pl)
{
     
	if(i<1 || i>L.length)
		return ERROR;
	pl = L.elem[i-1]; 
	return OK;
}
【作用解释】

火车头开始一个一个找,找到第i个车厢,并且将其中的数据返回到pl上。

【参数解释】

&:取地址符,为了让我们函数中形参的改变可以直接同步到实参上,我们可以在参数前加一个&。如果你听不懂我在说什么,你只要知道:加了这个之后,你函数内该量的改变,会导致函数外该量同时改变。

思路:
  1. 问问火车头我们有没有那么长,
    if(i<1 || i>L.length)return ERROR;如果我们的车厢并没有i那么长(i小于1,或者大于我们当前的最长长度),那我们找你马呢。(直接结束程序,气死老子了,不找了)
  2. 如果有那么长,我们就把对应地址的player给了pl
    pl = L.elem[i-1];

至于这里为什么用i-1……你应该懂,这里的i表示的是一般人认知中的第几个(正常人认知数是从第1个开始的),而我们的数组是从0开始的。

当然,如果你将其改成能够直接用i表示的,我会更开心。

5,函数_查询

Status LocateElem_Sq(Sqlist L,double e)
{
     
	for(itn i=0;i<L.length;i++)
	{
     
		if(L.elem[i].pow == e)
		{
     
			return i+1;
		}
	}
} 
【作用解释】

火车头开始一个一个找,找到第1个和e值数据相同的位置,并且将其编号返回。

在这里我使用的是playerpow的值,根据情况你也可以使用其他。

本函数非常简单,就是一个循环,一个一个找嘛,不寒颤。

找到那个对应等于e的值,然后返回i+1。(至于为什么是i+1,看刚刚的解释。

6,函数_插入

Status ListInsert_Sq(Sqlist &L,int i,player pl)
{
     
	if(i<1 || (i>L.length + 1))return ERROR;
	if(L.length == MAXSIZE)return ERROR; 
	
	for(int j=L.length-1;j>=i;j--)
	{
     
		L.elem[j+1]=L.elem[j];
	}
	
	L.elem[i-1] =pl;
	++L.length;
	return OK; 
} 
【作用解释】

pl插入到顺序表中的第i个位置。(注意,这里的i也是我们常人理解中从1开始的i)

思路:
  1. 先确定是不是在火车头范围内,我们一共就6节车厢,你总不能让我插入到第100节之后。
    if(i<1 || (i>L.length + 1))return ERROR;
  2. 确定我们现在的长度是不是已经到火车可以容纳的最大长度了。如果是的话,我们肯定不能再往里加了。
    if(L.length == MAXSIZE)return ERROR;
  3. 我们如果想往一列火车里塞一辆车进去……肯定不可能直接塞进去,我们需要先让后面的火车给它让开位置
for(int j=L.length-1;j>=i;j--)
	{
     
		L.elem[j+1]=L.elem[j];
	}

思路也很简单,就是从目前有的最后一个车厢开始,每个车厢向后移一格,一直到第i个

  1. 把我们的pl(数据名)存入这个位置,然后长度+1。
	L.elem[i-1] =pl;
	++L.length;

7,函数_删除

Status ListDelete_Sq(SqList &L, int i)
{
     
	if ((i < 1) || (i > L.length))return ERROR;
	
	for (int j = i; j <= L.length; j++)
		L.elem[j - 1] = L.elem[j];
		
	--L.length;
	
	return OK;
}
【作用解释】

删掉顺序表中的第i个值。

思路:
  1. 先确定是不是在范围内
    if ((i < 1) || (i > L.length))return ERROR;
  2. 将后一个车厢以此前移一格,来顶替掉之前车厢的位置。
    我举个栗子:
    原本有5格车厢(1,2,3,4,5)长度为5,我们要删掉第3格
    那么用第4格顶替第3格,用第5格顶替第4格,然后无视掉第5格。(你也可以把它给清零。)最长度-1变为4。现在就成了(1,2,4,5
for (int j = i; j <= L.length; j++)
		L.elem[j - 1] = L.elem[j];
  1. 长度-1
    --L.length;

如果你是初学者:

我建议你再尝试自己实现以下几个功能:

  • 清空顺序表
  • 销毁顺序表并重新定义长度
  • 输入e,查询线性表中该值出现过几次
  • 输入e,i,返回顺序表中第i次出现e是在哪个位置

如果你想要没有注释的代码:

拿走,请。

#include
#include
#include
#include

using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2

typedef int Status;
typedef int ElemType;

#define MAXSIZE 100	

struct player
{
     
	int id;
	string name;
	char pow,def,spe,nok;
};

typedef struct
{
     
	player *elem;
	int length;
}Sqlist;


Status InitList_Sq(Sqlist &L)
{
     
	L.elem = new player[MAXSIZE];
	if(!L.elem)exit(OVERFLOW);
	L.length =0;
	return OK;
}

Status GetElem(Sqlist L,int i,palyer &pl)
{
     
	if(i<1 || i>L.length) 
		return ERROR;
	pl = L.elem[i-1]; 
	return OK;
	
}

Status LocateElem_Sq(Sqlist L,double e)
{
     
	for(itn i=0;i<L.length;i++)
	{
     
		if(L.elem[i].pow == e)
		{
     
			return i+1;
		}
	}
} 

Status ListInsert_Sq(Sqlist &L,int i,player pl)
{
     
	if(i<1 || (i>L.length + 1))
	{
     
		return ERROR;
	}
	
	if(L.length == MAXSIZE)
	{
     
		return ERROR;
	} 
	
	for(int j=L.length-1;j>=i;j--)
	{
     
		L.elem[j+1]=L.elem[j];/ 
	}
	L.elem[i-1] =pl;
	++L.length;
	return OK; 
} 

Status ListDelete_Sq(SqList &L, int i)
{
     
	if ((i < 1) || (i > L.length))
		return ERROR; 
	for (int j = i; j <= L.length; j++)
		L.elem[j - 1] = L.elem[j];
	--L.length; 
	return OK;
}

int main()
{
     
	return 0;
} 


你可能感兴趣的:(顺序表,数据结构,c语言)