链表的特点:用一组任意的储存单元储存线性表的数据元素。
结点(存储印象):1.储存本身的信息~~数据域
2.储存直接后继元素的储存位置(一个指示其后继元素的信息)~~指针域
补充:1.链\指针:指针域中存储的信息
2. 链表:由n个结点链结成
头指针:链表中第一个结点的存储位置
头结点:1.有时我们会在第一个结点之前附设一个结点
2. 其数据域一般不放数据,但也可存储如线性表的长度等的附加信息
3.其指针域存储指向第一个结点的指针
首元结点:链表中第一个元素所在的结点,头结点后边的第一个结点
线性表的单链表储存结构:
typedef struct LNode{ //结点的类型定义(结构体类型)
Elentype data; //结点的数据域
struct LNode *next; //结点的指针域:一个指针,变量名叫next,类型是struct Lnode
}LNode,*Linklist;
解释:
1.elen:是单词element的缩写,意为在程序定义中代表某一不确定的类型,也就是抽象的数据类型。为了使程序可读性强,并且便于修改,让elem代表多种的数据类型,也就是为int、char等等的数据类型,起了一个别名。
2.ElemType是数据结构的书上为了说明问题而用的一个词。它是element type(“元素的类型”)的简化体。因为数据结构是讨论抽象的数据结构和算法的,一种结构中元素的类型不一定是整型、字符型、浮点型或者用户自定义类型,为了不重复说明,使用过程中用“elemtype”代表所有可能的数据类型,简单明了的概括了整体。在算法中,除特别说明外,规定ElemType的默认是int型。在头文件中定义:
typedef char elem;
抽象元素类型为char类型,这样定义之后,下面的程序中elem所定义的元素就是char类型的了
又例如,使用:typedef int ElemType; 定义ElemType为int类型
3.括号外的*Linklist是当前这个值的地址,只是这个值里有数据data,和下一个值的地址(指向这一结构体的一个指针)
4.括号里的是一个指针,变量名叫next,类型是struct Lnode*
5.括号外LNode是对struct LNode结构体的重命名
存储顺序:
若p指向的是第i个数据元素的指针,则p->next是指向第i+1个数据元素的指针。
即:若p->data=ai,则p->next->data=ai+1
补充:单链表中要取得第i个元素就必须从头指针出发寻找,因为,单链表是非随机存储的。
来看例题吧π-π
eg1:一个书上的例子~函数GetElem在单链表中的表现
Status GetElem_L(LinList L,int i,ElemType &e)//定义一个名叫GetElem_L的单链表
{ //L为带头结点的单链表的头指针
p=L->next;
j=1; //p指向的是首元结点,j为计数器
while(p&&j<i)//按顺序查找,直到p指向第i个指针或者p为空
{
p=p->next;
++j;
}
if(!p||j>i)//第i个元素不存在
return ERROR;
e=p->data;//第i个元素存在且取到了
return OK;
}
解释:
1.数据结构中status 的意思
算法开头status 是一种数据类型的别名,这单词是状态的意思,如返回 的是状态信息,就用status 声明函数返回类型。而通常用以下的语句说明status:如typedef int status ;这说明其实status和int 型是相同的,它大致上是用来返回本函数是否执行成功,它的几个取值OK,ERROR,OVERFLOW也在同时定义使用的时候把这些东西定义成一个头文件,使用Stauts的文件,包含这个头文件即可
2.线性表表函数GetElem(L,i,&e)是用e返回L中第i个元素的值.
3.if(!p||j>i)return ERROR;
这句我不晓得是啥意思,好难啊我不想学了气死了我哭了
单链表中我们怎样才能实现插入呢?
1.已知:要在a结点和b结点之间插入一个结点x,p为单链表存储结构中指向结点a的指针
2.思路:为在a结点和b结点插入数据x,首先要生成一个数据域为x的结点,然后插入单链表中;
然后修改结点a中的指针域,使其指向结点x;
结点x中的指针域应指向结点b。
3.假设:s为指向结点x的指针
4.实现语句为:
s->next=p->next; //结点x的指针域s指向下一个结点b的指针域,而b的指针域用一开始没有插入之前的的表示方式,即a结点的指针域p指向的下一个指针域
p->next=s; //p是结点a的指针域,指向下一个结点x的指针域s
单链表中我们怎样才能实现删除呢?
1.思路:仅需要修改结点a中的指针域
2.实现语句:
p->next=p->next->next;
总结:在单链表中插入或删除一个结点时,仅需修改指针而不需要修改移动元素。
例1:插入结点
Status ListInsert_L(LinkList &L,int i,Elemtype e)
{ //在L中的第i个位置之前插入元素e
p=L;
j=0;
while(p&&j<i-1)//寻找第i-1个结点
{
p=p->next;
++j;
}
if(!p||j>i-1)//第i个元素不存在
return ERROR;
s=(LinkList)malloc(sizeof(LNode));//开辟一个内存空间,存的是指针变量s
s->data=e; 结点s中的元素是e
s->next=p->next; //插入的结点s的下一个结点是原来没有插入时的下一个结点
p->next=s; //第一个结点p后面的结点不是next而是现在插入的结点s
return OK;
}
解释:
1.ListInsert(LinkList &L,int i,Elemtype e)链表函数:是用来在单链表L的第i个位置之前插入元素e,几个取值OK,ERROR,OVERFLOW。
2.malloc函数
int *p;
p = (int *)malloc( sizeof(int) );//malloc向系统申请一个sizeof(int)大小的内存空间
由系统生成一个LNode型的结点,同时将该结点的起始位置赋给指针变量p
例2:删除结点
Status ListDelete_L(LinkList &L,int i,Elemtype &e)
{
p=L;
j=0;
while(p->next&&j<i-1)
{
p=p->next;
++j;
}
if(!(p->next)||j>i-1)
return ERROR; //删除地方不合理时返回ERROR
q=p->next;
p->next=q->next;
e=q->data;
free(q); //删除并释放结点
return OK;
}
解释:
1.free(e):由系统回收一个结点,回收后的空间可以备作再次生成结点时用。
结论:单链表的存储空间可以为多个链表共同享有,按系统需求使用生成,因此,建立线性表的链式储存结构的过程就是一个动态生成链表的过程。即从空表建起,依次建立各个元素结点,并逐个插入链表。
我这个先学到这了,然后等下一篇哇,我学不懂了,下一篇估摸着是头插法和尾插法吧。我学不会了完了完蛋了。