线性表–顺序表
说到线性表大家肯定都不陌生了,而顺序表又是线性表的一种简单结构
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作。1
线性表是干嘛的呢?这就涉及到了我们实际中数组的应用,在实际应用中,数组的容量内容并不是一成不变的,恰恰相反,我们很多时候需要的是一个特别的容器来储存我们需要的内容。每当我们需要一个容量内容可变的数组的时候我们都会头疼不已,而线性表就是来帮助我们解决这个问题的。
本文先声明可能出现错误,并且应该很少有一些标准化的语言出现。
因为我写的初衷是巩固自己(As a undergraduate),因为很多时候我也不会emmm,QAQ
0、头文件:写程序头文件肯定是必不可少的嘛
#include <iostream>
constexpr auto MAXSIZE = 105;
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
using namespace std;
1、初始化:众所周知,线性表是一种基于结构体而衍生出来的数据结构,因此我们在初始化的时候必不可少的是要使用结构体的
typedef struct {
ElemType *elem;
int length;
}List;
PS:线性表我会多时候会说成链表
2、基本功能:链表能有什么基本功能,不就是增删改查吗
2.1、构造一个链表:咳咳,话是这么说,路还得一步一步走
构造,怎么构造呢?上面也说了,链表是可变数组,因此我们也要用构造数组的方法就构造一个数组
因此在刚开始我们需要一个有最大长度的数组(可以很大,根据实际需要)。既然是构造,万一不成功怎么办呢?自然也需要一个成功的判定。之后将链表初始化为0即可。最后return 成功就好。
Status CreateList(List &L)
{
L.elem = new ElemType[MAXSIZE]; //生成
if (!L.elem) exit(OVERFLOW); //不成功
L.length = 0; //初始化长度
return 1;
}
2.2、删除,置空:
删除,置空听起来的区别是不大的。实际上也是如此,删除当然就是删掉整个内存空间,恢复内存的可用性;而置空就是将链表恢复到初始化的状态。
Status DestroyList(List &L)
{
if (L.elem) delete[] L.elem; //存在则销毁,使用delete
L.length = 0; L.elem = NULL; //清空长度以及对象空间
}
Status ClearList(List &L)
{
L.length = 0; //清空及长度等于0
}
2.3求链表长,判断是否为空
这都没啥好说的,直接上代码了
Status LengthList(List L)
{
return L.length; //返回长度
}
bool EmptyList(List L)
{
if (L.elem == 0) return true; //长度为0则确实为空
else return false;
}
2.4增删改查:四种基本操作嘛,当然还是会逐步分析的
2.4.1增加:增加的难点就是在于你需要改变元素在链表中的位置
怎么办呢,所谓增加不就是,在两个元素之间插入一个新的元素,然后将后面得元素依次后推一位即可啦。
当然,在末尾添加只需要直接添加即可。
温馨提示:无论何时都不要忘记将length+1
Status AddElem(List &L, ElemType e, int i) //在第i个位置添加e
{
if (i<1 || i>L.length + 1) return ERROR;
if (L.length == MAXSIZE) return ERROR;
for (int j = L.length - 1; j >= i - 1; j--) //L的最后一个到第i个依次后移一位
{
L.elem[j + 1] = L.elem[j];
}
L.elem[i - 1] = e;
++L.length;
return OK;
}
Status AddElem(List &L, ElemType e) //在末尾添加元素
{
if (L.length == MAXSIZE) return ERROR;
L.elem[L.length] = e;
++L.length;
return OK;
}
2.4.2删除:所谓删除就是和增加恰恰相反,但是删除不一定是删除某个位置的了,可能是删除某个特定的元素。
以下列举了可能出现的情况:
Status DeleteElem(List &L, int i) //删除第i个位置的元素
{
if (i<1 || i>L.length + 1) return ERROR;
for (int j = i; j < L.length; j--) //L的第i+1个(下标为i)到最后一个依次前移一位
{
L.elem[j - 1] = L.elem[j];
}
--L.length;
return OK;
}
Status DeleteElem(List &L, ElemType e) //删除第一个e,类比查找还能重构数种
{
int i = FindFirstElem(L, e); //第一个e的位置
if (i<1 || i>L.length + 1) return ERROR;
DeleteElem(L, i);
return OK;
}
Status DeleteAllElem(List &L, ElemType e) //删除所有的元素e
//找到第一个e,删除第一个,后面所有元素往前进一;
//之后边前进边查找,找到第二个,删除,后面所有元素进二;以此类推。
{
int n = 0; //每次需要进位数
for (int i = 0; i < L.length; i++) //遍历一次,每一次执行:是否是e,若是n++;若不是向前进n位;
{
if (e == L.elem[i])
{
n++;
}
else
{
L.elem[i - n] = L.elem[i];
}
}
L.length -= n; //共删去几个长度减几
return OK;
}
删除所有的我要吭一句:老师让用的是O(n)时间复杂度的方法,现在你应该能看懂了吧。
2.4.3改:改不就是直接替换嘛,这里就不写了也不放代码了
我可不会告诉你们因为我自己没敲
2.4.4查找:这里给出通过指针带出或者返回值带出两种,个人喜欢后者,但是不知道为什么老师讲了第一种
Status GetElem(List L, int i, ElemType &e) //通过e带出
{
if (i<1 || i>L.length) return ERROR;
else e = L.elem[i - 1]; //第i个实际下标为i-1
return OK;
}
Status GetElem(List L, int i) //通过返回值得到
{
if (i<1 || i>L.length) return ERROR;
return L.elem[i - 1];
}
当然查找肯定不限于只有这些,比如删除会删去所有e,当然你可以查找所有e的位置,然后用数组带出。
有规律的链表你可以用各种查找算法啊都是可以很方便的实现的,这里就不一一赘述的,当然不是因为我懒。
3:额外功能
唔,什么是额外功能呢,那当然你制造出来链表不能只局限于一个咯。比如并交差补啊很多两个或以上链表的相互操作。这里放上我已经写好的,比较晚了多的我也不写了。
交集:查找相同的放到新的链表中:你也可以根据需要指针带入,最终由其中一个带出。
并集:我采用的方法是两个加到一起再减去交集(集合相减:这是个差吗),主要还是不想再写新方法了,用现有的改变一下它不香吗。
后来我才意识到: 集合的话,不会有重复元素的 啊啊啊awsl,这么多年学白上了。
小生愚昧,愿后来者不要像我一样犯这种低级错误。
List InterList(List L1,List L2) //交集
{
List newList;
CreateList(newList);
for (int i = 0; i < L1.length; i++)
{
for (int j = 0; j < L2.length; j++)
{
if (L1.elem[i] == L2.elem[j]) //两个集合中有相同的元素
{
AddElem(newList, L1.elem[i]); //添加到新的交集中
newList.length++; //不要忘记长度加一
DeleteElem(L2, L1.elem[i]); //删掉第二个集合中的该元素,不删第一个的原因是,第一个集合只遍历一次无影响
//而且如果删掉,会影响L1.length,而删第二个因为每次二重循环重新开始L2.length无所谓
break; //退出该次循环,不然可能一次删掉多个重复元素
}
}
} //???重复元素,一个集合能有两个重复元素吗
return newList;
}
List UnionList(List L1,List L2) //并集:加一起删掉交集
{
List tempList;
tempList = InterList(L1, L2); //求交集
for (int i = 0; i < L2.length; i++) //L1=L1+L2
{
AddElem(L1, L2.elem[i]);
}
for (int i = 0; i < tempList.length; i++) //合集-=交集
{
DeleteElem(L1, tempList.elem[i]);
}
L1.length -= tempList.length; //长度也是如此
return L1;
}
最后声明:本篇内容代码暂未经过测试,仅为demo版本,如果我测试了,我一定会回来更新的。
如果我长时间没来,那就说明,我咕了嘻嘻
原作者:凡尘戏梦——一个不正经的大学生
2020/3/5 23:05记录第一次正式开始写博客(不正式的都不作数)
本段话来自360百科 ↩︎