面试题经常会问到单链表的增删改查,我现在详细解决一下这些问题。我个人很是喜欢删除的第二种解法,很是犀利。
此篇博客还有面试经常问的一个问题:单链表如何就地逆置?网上的解法众说纷纭,很多都没讲明白,我自己写了一种,觉得倒是干净利落。
首先将头结点断开,然后将后面的结点依次进行头插法建立链表就OK了。
#include<stdio.h>
typedef struct List *link;
struct List
{
int num;
link next;
};
link head = NULL;
link insert(int i)
{
link p = malloc(sizeof(*p));
p->num = i;
p->next = head;
head = p;
return head;
}
void bianli()
{
link p = head;
while(p!=NULL)
{
printf("%4d",p->num);
p=p->next;
}
printf("\n");
/* if(p!=NULL) //注释的是用递归实现单链表的逆序输出。
{
bianli(p->next);
printf("%4d",p->num);
}*/
}
void reserve() //单链表的逆置,首先将头结点断开,依次进行一次头插法就OK了。
{
link p = head;
link q;
head = NULL;
while(p!=NULL)
{
q = p->next;
p->next = head;
head = p;
p = q;
}
}
link search(int key)
{
link p = head;
while(p != NULL)
{
if(p->num == key)
{
printf("FIND KEY\n");
return p;
}
p = p->next;
}
printf("NOT FIND KEY\n");
return NULL;
}
void delete(link p)
{
link pre;
if(p == head)
{
head = p->next;
free(p);
}
else
{
for(pre=head;pre!=NULL;pre=pre->next)
if(pre->next == p)
{
pre->next = p->next;
free(p);
}
}
}
/*
定义一个指向指针的指针pnext,在for循环中pnext遍历的是指向链表中各节点的指针域,
这样就把head指针和各节点的next指针统一起来了,可以在一个循环中处理。
*/
void delete_next(link p)
{
link *pnext;
for(pnext=&head;*pnext;pnext=&(*pnext)->next)
{
if(*pnext == p)
{
*pnext = p->next;
free(p);
return; //此处必须添加return;否则删除最后一个结点会出现段错误,谁能告诉我这是为什么?
}
}
}
int main(int argc,char *argv[])
{
link p;
int i;
for(i=1;i<10;i++)
insert(i);
bianli(head);
reserve();
bianli();
p = search(6);
//delete(p);
delete_next(p);
bianli();
return 0;
}