考纲要求:在算法实现方面要求,能够根据实际问题的需求来决定采用何种存储结构并给出具体的算法,如:插入、删除满足条件的链表节点,在链表上排序等。
一、插入类
1,有一个有序单链表L(从小到大排列),设计将x插入新线性表适当位置的算法。
void inorderList(LinkList *&L,ElemType x)
{ LinkList *s,*pre,*p;
s=(LinkList *)malloc(sizeof(LinkList)); //建立一个待插入的节点*s
s->data=x;s->next=NULL;
pre=L; p=pre->next; //pre、p指向头节点和第一个数据节点
while (p!=NULL && p->data<x) //找刚好大于或等于x的节点*p
{ pre=p;
p=p->next; //pre、p同步后移一个节点
}
s->next=pre->next; //将*s节点插入到*pre节点之后
pre->next=s;
}
二、删除类
1,设计一个算法删除单链表L中第一个值为x的结点。
示意图如下:
int delx(LinkList *&L,ElemType x)
{ LinkList *pre=L,*p=pre->next; //pre指向*p的前驱节点
while (p!=NULL && p->data!=x)
{ pre=p;
p=p->next; //pre、p同步后移一个节点
}
if (p!=NULL) //找到值为x的*p节点
{ pre->next=p->next;
free(p);
return 1;
}
else return 0; //未找到值为x的节点
}
2,在带头结点的单链表中删除一个最小值的节点算法。
void delminnode(LinkList *&L)
{ LinkList *pre=L,*p=pre->next,*minp=p,*minpre=pre;
while (p!=NULL) //查找最小值节点*minp及其前驱节点*minpre
{ if (p->data<minp->data)
{ minp=p; //将较小的节点*p存入minp中
minpre=pre; //将较小的节点的前驱*pre存入minpre中
}
pre=p; //pre、p同步后移
p=p->next;
}
minpre->next=minp->next; //删除*minp节点
free(minp);
}
3,设计一个算法删除并释放以L为表头指针的单链表的所有节点。
void DestrogList(LinkList *&L)
{ LinkList *pre=L,*p=L->next;
while (p!=NULL)
{ free(pre);
pre=p; //pre、p同步后移
p=p->next;
}
free(pre); //当p=NULL时还需释放*pre节点
}
三、排序类
1,设计一个算法判定单链表L的所有结点值是否是递增的。
int increase(LinkList *L)
{ LinkList *pre=L->next,*p; //pre指向第一个数据节点
p=pre->next; //p指向*pre节点的后继节点
while (p!=NULL)
{ if (p->data>=pre->data) //若正序则继续判断下一个节点
{ pre=p; //pre、p同步后移
p=p->next;
}
else return 0;
}
return 1;
}
2,假设有两个按元素值递增排序的线性表,均以单链表形式存储,编写算法将两个单链表归并为一个按元素值递减排序的单链表,并要求利用单链表的结点归并后存放在新的单链表中。
LinkedList Union(LinkedList la,lb)
{
pa=la->next;pb=lb->next; //pa,pb为la,lb的指针
la->next=null; //将la作为结果链表,将结果链表的初始化为空
while(pa!=null && pb!=null ) //当两链表均不为空时
if(pa->data<=pb->data){
r=pa->next; //将pa后继存储标记r
pa->next=la->next; //将pa存入结果链表,同时逆置,实质就是头插法建立单链表
la->next=pa;
pa=r;
}
else{
r=pb->next;
pb->next=la->next;
la->next=pb;
pb=r;
}
if(pa) pb=pa;
while(pb!=null){
r=pb->next;pb->next=la->next;la->next=pb;pb=r;
}
}
3,有一个线性表(a1,a2,…,an),其中n≥2,采用带头节点的单链表L存储,设计一个算法将其就地逆置。所谓“就地”是指辅助空间应为O(1)。
void Reverse1(LinkList *&L)
{ LinkList *p=L->next,*q;
L->next=NULL; //将L看成只有一个头节点的空表
while (p!=NULL) //用p遍历余下的节点
{ q=p->next; //用q临时保存*p的后继节点
p->next=L->next; //将*p节点插入到新建链表的前面
L->next=p;
p=q; //p继续遍历余下的节点
}
}
实质:采用头插法重新建立单链表。
4,有一个整数元素建立的单链表A,设计一个算法,将其拆分成两个单链表A和B,使得A单链表中含有所有的偶数节点,B单链表中含有所有的奇数节点,且保持原来的相对次序。
void Split(LinkList *&A,LinkList *&B)
{ LinkList *p=A->next,*ra,*rb;
ra=A;
B=(LinkList *)malloc(sizeof(LinkList)); //建立头节点
rb=B; //r总是指向B链表的尾节点
while (p!=NULL)
{ if (p->data%2==0) //偶数节点
{ ra->next=p; //将*p节点链到A中
ra=p;
p=p->next;
}
else //奇数节点
{ rb->next=p; //将*p节点链到B中
rb=p;
p=p->next;
}
}
ra->next=rb->next=NULL;
}
实质:采用尾插法重新建立单链表。
四、拓展 与递归相结合
1,有一个不带表头节点的单链表,其节点类型如下:
typedef struct NodeType
{ ElemType data;
struct NodeType *next;
} NodeType;
设计如下递归算法:
(1)求以h为首指针的单链表的节点个数。
int count(NodeType *h)
{ if (h==NULL)
return 0;
else
return(1+count(h->next));
}
(2)正向显示以h为首指针的单链表的所有节点值。
void traverse(NodeType *h)
{ if (h!=NULL)
{ printf("%d ",h->data);
traverse(h->next);
}
}
(3)反向显示以h为首指针的单链表的所有节点值。
void revtraverse(NodeType *h) //算法(3)
{ if (h!=NULL)
{ revtraverse(h->next);
printf("%d ",h->data);
}
}
(4)删除以h为首指针的单链表中值为x的第一个节点。
void delnode(NodeType *&h,ElemType x) //算法(4)
{ NodeType *p;
if (h!=NULL)
{ if (h->data==x) //若首节点值为x
{ p=h;
h=h->next;
free(p);
}
else //若首节点值不为x
delnode(h->next,x);
}
}
(5)删除以h为首指针的单链表中值为x的所有节点。
void delall(NodeType *&h,ElemType x) //算法(5)
{ NodeType *p;
if (h!=NULL)
{ if (h->data==x) //若首节点值为x
{ p=h;
h=h->next;
free(p);
delall(h,x); //在后继节点递归删除
}
else //若首节点值不为x
delall(h->next,x); //在后继节点递归删除
}
}
(6)输出以h为首指针的单链表中最大节点值。
ElemType maxv(NodeType *h)
{ ElemType m;
if (h->next==NULL) //只有一个节点的情况
return(h->data);
m=maxv(h->next); //求后继节点的最大值
if (m>h->data)
return m;
else
return h->data;
}
(7)输出以h为首指针的单链表中最小节点值。
ElemType minv(NodeType *h) //算法(7)
{ ElemType m;
if (h->next==NULL)
return h->data;
m=minv(h->next);
if (m>h->data)
return h->data;
else
return m;
}
(8)删除并释放以h为首指针的单链表中所有节点。
void release(NodeType *h) //算法(8)
{ if (h!=NULL)
{ release(h->next);
free(h); //释放*h节点
}
}
求解方法归纳:
基于建表的算法:这类算法直接或间接地转换成建表过程,如果新建表的次序与原来的次序相同,则采用尾插法;如果新建表的次序与原来的次序相反,则采用头插法。
基于查找、插入或删除的算法:这类算法以单链表的基本运算为基础,包含有节点的查找、插入或删除操作