这种题目数据结构特别爱考,本文做一个总结。
常见的三种题型有:
①增、增→减
②增、增→增
③增→序号为奇的、序号为偶的(增、增)
1、增增合并为递减
不建立新表,增增→减,采用头插法。
如: A-p:2356 B-q:12578 为例
第一次循环 A:1;第二次循环 B删掉2,A:21 ;第三次循环 3>5,A:321;
第四次循环 A:5321 ;第五次循环 A:65321 ;第六次条件不满足,A为空,B头插接上剩下的。
此算法得到递减的链表。
//增增→减
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
LinkList merge(LinkList A,LinkList B){
LinkList p=A->next,q=B->next,s=NULL;
A->next=NULL; //把A与后面的元素脱离,要作为工作的表
while(p&&q){
if(p->data > q->data){ //把最小的拿出来
s=q->next;
q->next=A->next;
A->next=q;
q=s;
}
else if(p->data == q->data){
s=q;
q=q->next;
B->next=s->next; //保证链表不断开
free(s);
s=p->next; //删了q,但是p要加入链表,所以s跑来帮p定位下一个元素
p->next=A->next;A->next=p;p=s; //p恢复
}
else{
s=p->next;
p->next=A->next;A->next=p;p=s;
}
}
if(p)
q=p; //多余的元素
while(q){
s=q->next;
q->next=A->next;A->next=q;q=s;
}
free(B);
}
2、增增合并为递增
在上一个算法基础上,加一个逆置算法(头插)即可得到递增。
void reverse(linklist A){
linklist p,s;
p=A->next;L->next=NULL;
while(p){
s=p->next; //固定下一个位置
p->next=L->next;
L->next=p;
p=s; //回到下一个位置
}
}
也可以使用尾插法(可用的题目较少):
LinkList mergelist(LinkList La,LinkList Lb){
LinkList *pa=La->next,*pb=Lb->next,*pc=La,q;
La->next=NULL;
while (pa&&pb){ //当pa或者pb其中有一个链为空时停止循环
if(pa->data<pb->data){ //pa小于pb时
pc->next = pa; //保证链表的连续
pc=pa; //pc向后走
pa=pa->next; //pa向后走 最关键的两步,尾插
}
else if(pa->data==pb->data){ //pa等于pb时
pc->next=pa; //连接
pc=pa;
pa=pa->next; //往后走
q=pb;
pb=pb->next;
free(q)
}
else { //大于pb时
pc->next = pb;
pc=pb;
pb=pb->next;
}
}
pc->next = pa?pa:pb; //另一种连接剩余链表的方式,非空则A,空则B
free(Lb);
return La;
}
3、增分解为奇偶序号的两条链表
LA是原表中奇序号的元素,LB是偶序号的元素。
LinkList DisCreat(LinkList &A){
int i = 0;
B = (LinkList)malloc(sizeof(LNode));
B->next = NULL; //B表初始化
LNode *ra = A,*rb = B; //分别指向AB两表
p = A->next; //p为工作指针
A->next = NULL;
while(p != NULL){
i++;
if(i&2 == 0){ //序号为偶
rb->next = p; //插入rb表
rb = p; //指向新的尾节点
}else{ //序号为奇
ra->next = p;
ra = p;
}
p = p->next; //p 往前走
}
ra->next = NULL;
rb->next = NULL;
return B;
}