1、链表:链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,查找一个节点或者访问特定编号的节点则需要O(n)的时间
2、链表的声名与定义:
typedef struct node
{
int nval; //数据域
struct node *pnext; //指针域
}list;
3、链表的创建:
list *createnode()
{
list *phead = NULL;
list *pend = NULL;
list *ptmp = NULL;
int cnt ;
int n;
scanf("%d",&cnt);
while(cnt>0)
{
scanf("%d",&n);
ptmp = (list *)malloc(sizeof(list));
ptmp->nval = n;
ptmp->pnext = NULL;
if(phead == NULL)
{
phead = ptmp;
}
else
{
pend->pnext = ptmp;
}
pend = ptmp;
cnt--;
}
return phead;
}
4、链表的打印:链表的输出可以是非递归的,也可以是递归的。
void outputnode(list *pnode) //非递归打印链表
{
while(pnode != NULL)
{
printf("%d ",pnode->nval);
pnode = pnode->pnext;
}
}
void diguioutputnode(list *pnode) //递归打印链表
{
if(pnode != NULL) //如果该节点不是空,那么打印下一个
{
printf("%d ",pnode->nval);
diguioutputnode(pnode->pnext);
}
}
5.链表的逆序输出问题:我给出三种方法:第一种是将链表输入到数组中,再逆序输出;第二种方法是递归逆序打印链表想法类似于顺序递归打印;第三种方法是直接将原链表倒置。
void reverse_output(list *pnode) //方法一:输入数组,逆序打印数组
{
if(pnode==NULL) return ;
int len = 0;
int i = 0;
list *pmark = pnode;
while(pmark!=NULL)
{
len++;
pmark = pmark->pnext;
}
int *p = (int *)malloc(sizeof(int)*len);
while(pnode != NULL)
{
p[i] = pnode->nval;
pnode = pnode->pnext;
i++;
}
for(i=len-1;i>=0;i--)
{
printf("%d ",p[i]);
}
free(p);
p = NULL;
}
list *reverse_list(list *phead) //方法二:将链表倒置
{
list *p1 = NULL;
list *p2 = phead;
list *p3 = phead->pnext;
while(p3!=NULL)
{
p2->pnext = p1;
p1 = p2;
p2 = p3;
p3 = p3->pnext;
}
p2->pnext = p1;
return p2;
}
void digui_reverseoutputlist(list *phead) //方法三:递归逆序链表
{
if(phead == NULL) //节点为空不打印
{
return ;
}
else //节点不为空打印下一个;最后打印当前节点。
{
digui_reverseoutputlist(phead->pnext);
printf("%d ",phead->nval);
}
}
对于方法二的实现解释:
新建三个指针p2指向链表的头节点,p3指向链表的头节点的下一个节点(即phead->pnext),p1初值为空,将三个指针作为链表的三个节点顺着链表移动,当中将每一个节点的指向下一个节点指针(即p2->pnext)赋值为前一个节点(即p1)上。最后,要有一个p3作为边界条件,断开后让原链表的尾节点(p2)作为新链表的头,并且连接上新的链表,返回p2即可。
程序截图: