链表
1.链表的意义
我们原本习惯用数组来处理大量的数据,但是数组的本质是线性表,对于数据的读取,其时间复杂度为O(1),并且数组本身所占的空间很小,不需要额外的存储空间来存储逻辑关系。但数组也有缺点,对于数据的插入与删除,大家估计想想就头痛,就好比一群人在排队,一个人插了你的队,从你到队列的最后一个人都要往后走几步,此时心里一万只草泥马跑过。。。所以我们引入了链表这个结构,它可以让插入,删除操作的时间复杂度极大的简化。
2.链表的结构
我们可以想象一个银行,里面的人与排队不同,而是松散地处于银行各处,要确定他们之间的顺序,有一个很好的办法:让每个人的手上拿着下一个顾客位置的纸片,每办完业务之后,就去通知下一个顾客,而我们所要做的就是记住第一个顾客的位置。所以具体而言每一个顾客(数据)拥有着两个类型的数据,即:原本的信息——数据域,下一个人的位置——指针域。我们还称每个“顾客”为节点。链表的本质就是一连串排列不规则却拥有逻辑顺序(先后顺序)的节点的集合。顺便说一下,这样的结构占地位置更大(额外要储存指针变量),而内存的栈区的储存很有限,对于大量的数据,我们推荐利用malloc函数开拓内存的堆区(很大)来储存。
以下是链表的概念图(本人灵魂画师,敬请见谅)。date为数据域,pnext为指向下一节点的指针(指针域)。
3.链表的实现
鉴于链表是由节点为主体,如果按照传统的写法,我们之后编写函数可能会造成链表和节点的混淆,无可避免会写得很复杂,最关键的是,体现不出面向对象的思维方式。我参考了大牛的代码,引入他的一个结构,该结构用于管理整个链表,我希望将这个结构称之为链表,以达到将节点与链表严格区分起来的目的。具体来说,这个结构存有三类数据:
1):指向第一个节点的指针 pfront
2):指向最后一个节点的指针 prear
3):记录整个链表的节点个数 count
我们可以通过这个结构让有关链表函数的结构看起来很清晰,同时体现面向对象。我们以List为链表,Node为节点,以下是具体的定义方法:
struct Node//定义节点
{
int data;//数据域
Node* pnext;//指向Node结构体的指针
}
struct List//定义链表
{
Node* pfront;//指向第一个节点的指针
Node* prear;//指向最后一个节点的指针
int count;//记录链表中节点个数
}
4. 有关链表的函数
1.先是链表的初始化
int initList(List**pplist)//传入一个想要指向List类型指针的地址(二级指针)
{
*pplist=(List*)malloc(sizeof(List));//开辟内存
if(*pplist!=NULL)//判断是否开辟内存成功
{
*pplist->pfront=NULL;//初始化,以下
*pplist->