默认带头结点
1.尾插法建单链表
假设有n个元素已经存储在数组a中,用尾插法建立链表C:
void CreatelistR (LNode *&C, int a[], int n) { //要改变的变量用引用型。
LNode *s, *r;
//s用来指向新申请的结点,r始终指向C的终端结点。
int i;
C = (LNode *)malloc(sizeof(LNode));
//申请C的头结点空间。
C->next = NULL;
r = C;
//r指向头结点,因为此时头结点就是终端结点。
for(i=1;i<=n;i++){ //循环申请n个结点来接受数组a中的元素。
s = (LNode *)malloc(sizeof(LNode));
//s指向新申请的结点。
s->data = a[i];
//用新申请的结点来接受a中的一个元素。
r->next = s;
//用r来接纳新结点。
r = r->next;
//r指向终端结,点以便于接纳下一个到来的结点。
}
r->next=NULL;
//数组a中所有的元素都已经装入链表C中,C的终端结点的指//针域置为NULL,C建立完成。
}
2.头插法
在头插法算法中不断的将新结点插入链表的前端,因此新建立的链表中元素的次序和数组a中的元素的次序是相反的。
代码如下:
void CreatelistF (LNode *&C,int a[],int n) {
LNode *s;
int i;
C = (LNode *)malloc(sizeof(LNode));
C->next = NULL;
for(i = 1; i< = n; i++){
s = (LNode*)malloc(sizeof(LNode));
s->data = a[i];
/*下边两句是头插法的关键步骤。*/
s->next = C->next;
//s所指新结点的指针域next指向C中的开始结点。
C->next = s;
//头结点的指针域next指向s结点,使得s成为了新的开始结点。
}
}
3.递增归并单链表:
假设A和B是两个单链表(带表头结点),其中元素递增有序。设计一个算法将A和B归并成一个按元素递增有序的链表C,C由A和B中的结点组成。
分析:
已知A,B中的元素递增有序,可以从A,B中挑出最小的元素插入C的尾部,这样当A,B中所有元素都插入C中的时候,C一定是递增有序的。由于A,B是递增的,所以A中的最小元素是其开始结点中的元素,B也一样。只需从A,B的开始结点中选出一个较小的来插入C的尾部即可。这里还需注意,A与B中的元素有可能一个已经全部被插入到C中,另一个还没有插完,比如A中所有元素已经全部被插入到C中而B还没有插完,这说明B中所有元素都大于C中元素,因此只要将B链接到C的尾部即可,如果A没有插完则用类似的方法来解决。
void merge (LNode *&A, LNode *&B, LNode *&C){
LNode*p = A->next;
//p来跟踪A的最小值结点。
LNode*q = B->next;
//q来跟踪B的最小值结点。
LNode*r;
//r始终指向C的终端结点。
C = A;
//用A的头结点来做C的头结点。
C->next = NULL;
free(B);
//B的头结点已无用,则释放掉。
r = C;
//r指向C,因为此时头结点也是终端结点。
while(p! = NULL&&q! = NULL){ //当p与q都不空时选取p与q所指结点中的较小者插入C的尾部。
/*以下的ifelse语句中,r始终指向当前链表的终端节点,作为接纳新结 点的一个媒介,通过它新结点被链接入C并且重新指向新的终端结点以便于接受下一个新结点,这里体现了建立链表的尾插法思想。*/
if(p->data< = q->data) {
r->next = p;
p = p->next;
r = r->next;
} else {
r->next = q;
q = q->next;
r = r->next;
}
}
r->next = NULL;
/*以下两个if语句将还有剩余结点的链表链接在C的尾部*/
if(p! = NULL)
r->next = p;
if(q! = NULL)
r->next = q;
}
4.递减归并的单链表算法:
A和B是两个单链表(带表头结点),其中元素递增有序。设计一个算法将A和B归并成一个按元素递减有序的链表C,C由A和B中的结点组成。
将插入过程改成头插法即可解决。代码如下,这里不需要r追踪C的终端结点,用s来接受新的结点插入链表C的前端。
void merge (LNode *&A, LNode *&B, LNode *&C){
LNode *p = A->next;
LNode *q = B->next;
LNode *s;
C = A;
C->next = NULL;
free(B);
while(p! = NULL && q! = NULL) {
/*下边这个if else语句体现了链表的头插法*/
if(p->data <= q->data){
s = p;
p = p->next;
s->next = C->next;
C->next = s;
} else {
s = q;
q = q->next;
s->next = C->next;
C->next = s;
}
}
/*下边这两个循是和求递增归并序列不同的地方,必须将剩余元素逐个插入C的头 部才能得到最终的递减序列。*/
while(p != NULL) {
s = p;
p = p->next;
s->next = C->next;
C->next = s;
}
while(q! = NULL){
s = q;
q = q->next;
s->next = C->next;
C->next = s;
}
}
5.插入节点的关键步骤
q = p->next;
p->next = p->next->next;
注意:以上插入操作语句不可以颠倒顺序写成p->next=s; s->next=p->next;
,因为第一句p->next=s;虽然将s链接在p之后,但是同时也丢失了p直接后继结点的地址(p->next指针原本所存储的p直接后继结点的地址在没有被转存到其他地方的情况下被s所覆盖,而正确的写法中,p->next中的值在被覆盖前被转存在了s->next中,因而p后继结点的地址依然可以找到),这样链表断成了两截,没有满足将s插入链表的要求。
6.删除节点的关键步骤
要将单链表的第i个结点删去,必须先在单链表中找到第i-1个结点,再删除其后继结点。如下图所示,若要删除结点b,为了实现这一逻辑关系的变化,仅需要修改结点a中的指针域。假设p为指向a的指针。则只需将p的指针域next指向原来p的下一个结点的下一个结点即可。即:
q = p->next;
p->next = p->next->next;
删除节点范例
查找链表C(带头结点)中是否存在一个值为x的结点,存在就删除之并返回1,否则返回0。
分析:
对于本题需要解决两个问题,一是要找到值为x的结点;二是将找到的结点删除。。为了实现查找,我们定义一个结点指针变量p,让他沿着链表一直走到表尾,每来到一个新结点就检测其值是否为x,是则证明找到,不是则继续检测下一个结点。
int SearchAndDelete (LNode *&C, int x){
LNode*p,*q;
p = C;
/*查找部分开始*/
while(p->next! = NULL){
if(p->next->data == x)
break;
p = p->next;
}
/*查找部分结束*/
if(p->next == NULL)
return 0;
else{
/*删除部分开始*/
q = p->next;
p->next = p->next->next;
free(q);
/*删除部分结束*/
return 1;
}
}
说明:以上程序中之所以要使p指向所要删除结点的前驱结点而不是直接指向所要删除结点本身,是因为要删除一个结点必须知道其前驱结点的位置.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。