一、定义静态链表
代码如下:
struct Node{
int address;//结点地址
typename data;//数据域
int next;//指针域
XXX;//结点的某个性质,不同的题目会有不同的设置
}node[100010];
上面的定义中,我们把结点的地址、数据域、指针域都进行了定义,并且留了一个XXX来适应不同的题目(例如可以设置为结点是否为链表上的一个结点)
二、静态链表的初始化
在程序的开始,对静态链表进行初始化。一般来说,需要对定义中的XXX进行初始化,将其定义为正常情况下达不到的数字(一般来说需要小于所有能达到的数字,理由在第四步中说明)例如对结点是否在链表上这个性质来说,我们可以初始化为0(即false),表示结点不在链表上。
for(int i=0;i<maxn;i++){
node[i].XXX=0;
}
三、遍历链表
题目一般都会给出一条链表的首结点的地址,那么我们就可以依据这个地址来遍历得到整条链表。需要注意的是,这一步同时也是我们对结点的性质XXX进行标记,并且对有效结点的个数进行计数的时候,例如对结点是否在链表上这个性质来说,当我们遍历链表时,就可以把XXX置为1,即true
int p=begin,count=0;
while(p!=-1){
//-1代表链表结束
XXX=1;
count++;
p=node[p].next;
}
步骤四
由于使用静态链表时,是直接采用地址映射(hash)的方式,这就会使得数组下标的不连续,而很多时候题目中给出的结点并不都是有效结点(即可能存在不在链表上的结点)。为了能够可控的访问有效结点,一般都需要对数组进行排序以把有效结点移到数组左端,这样就可以用步骤3的count来访问它们;
既然需要把有效结点移到前面,那么就可以利用之前定义的XXX来帮忙,在步骤2中,XXX需要被初始化为比正常结点的XXX取值要小的数值,这个做法就可以在这一步起到作用吧,由于无效结点的XXX在步骤3中不会被修改,因此一定比有效结点的XXX小。于是在写sort的排序函数cmp时,就可以在cmp的两个参数结点中有无结点时按XXX从大到小排序,这样就可以把有效结点全部移到数组的左端。
一般来说,题目中还会有额外的要求,因此,cmp函数都需要有二级排序,不过这需要看具体的题目,例如:如果题目的要求需要把链表按照结点顺序排序,就需要在cmp函数中建立第二级排序,即在cmp的两个参数结点中有无效结点时按XXX从大到小排序,而当两个结点都是有效结点时,按照结点在链表中的位置从小到大排序(结点的顺序可以在第三步中得到)
bool cmp(Node a,Node b){
if(a.xxx==-1||b.xxx==-1){
//至少有一个结点是无效结点,就把它放在数组后面
return a.xxx>b.xxx;
}else{
//第二级排序
}
}
在经历了步骤四之后,链表中的有效结点就都在数组的左端了,且已经按照结点的性质进行了排序,接下来就是看题目的具体要求(比较常见的是按照各种不同的要求来输出链表)