您的位置:首页 > 理论基础 > 数据结构算法

链表的理解与实现[数据结构]

2016-01-27 14:02 951 查看

一、链表的定义

n个节点离散分配,节点之间通过指针相连。除了首节点和尾节点之外,每个节点都只有一个前驱结点和一个后继节点。

如下图:



大家有没有发现,链表的结构很像一种交通工具,什么呢?

火车。(节点==车厢,指针==车厢间相连的绳索)

二、链表的实现

注意,这里实现的是链表中最简单的单链表。

1、创建链表

1.1 定义链表最基本的组成元素–节点

我们由上面链表的定义可以知道,链表的每个节点应该含有两部分:

1、每个节点本身存储的数据,我们假定data 为 int 类型;

2、当前节点指向下一个节点的指针。

好,我们根据以上两部分进行节点的定义:

/**
NODE:节点类型
PNODE:指向节点的指针
*/
typedef struct Node
{
int data;
struct Node * pNext;
}NODE,*PNODE;


1.2创建链表

上面我们定义好了链表的节点,接下来我们就进入激动人心的一刻吧,创建属于你的链表!

上面讲了,链表的结构就像火车的结构,我们不妨以火车为例进行讲解吧!

1、创建火车头:

//PNODE是指向NODE节点的指针类型
PNODE pHead=(PNODE)malloc(sizeof(NODE));


完美!我们创造了一个火车头,并且使用pHead指向了这个火车头。

如下图:



2、创建火车尾部

    //PNODE是指向NODE节点的指针类型
PNODE pHead=(PNODE)malloc(sizeof(NODE));
//pTail是指向火车尾部的指针
PNODE pTail=pHead;
pHead->pNext=NULL;


由于现在只有一节车厢,所以pHead和pTail都指向这节车厢。

如下图:



3、添加车厢

//假设我们添加3节车厢
for(i=0;i<3;i++)
{
printf("请输入第%d节车厢的数值\n",i+1);
scanf("%d",&val);
PNODE pNew=(PNODE)malloc(sizeof(NODE));
pNew->data=val;
pTail->pNext=pNew;
pTail=pNew;
pNew->pNext=NULL;
}


当i=0的时候,我们添加1节车厢,假设第1节车厢存储的值为1。

结构从



变为



上述pTail=pNew,使得pTail指向pNew指向的节点。

当i=1的时候,我们添加第2节车厢,假设第2节车厢存储的值为2。



当i=3的时候,同理添加第3节车厢。

如此,3节车厢就添加完了。

注意,pTail的作用是始终指向最后一节车厢,方便添加新车厢。

添加车厢的时候直接让pTail指向新的车厢,再让pTail指向新添加的车厢(最后一节车厢)。

总体代码:

//
typedef struct Node
{
int data;
struct Node * pNext;
}NODE,*PNODE;
//创建链表
PNODE createList()
{
int i,val,n;
PNODE pHead=(PNODE)malloc(sizeof(NODE));
PNODE pTail=pHead;
pHead->pNext=NULL;
printf("请输入链表长度:");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("请输入第%d个数值\n",i+1);
scanf("%d",&val);
PNODE pNew=(PNODE)malloc(sizeof(NODE));
pNew->data=val;
pTail->pNext=pNew;
pTail=pNew;
pNew->pNext=NULL;
}
//将指向火车头的指针返回
return pHead;
}


2、遍历链表

2.1判断链表是否为空

我们要遍历一个链表,首先要判断链表是否为空。

链表空的话,我们就直接返回,不遍历。

/**
返回1:链表为空
返回0:链表不空
*/
//判断链表是否为空
int isEmpty(PNODE pHead)
{
if(pHead->pNext==NULL)
{
return 1;
}
else
{
return 0;
}
}


2.2遍历链表

如果链表不空的话,我们就进行如下遍历

PNODE p=pHead->pNext;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->pNext;
}


我们定义一个指针p

PNODE p=pHead->pNext;使得p指向了第1节车厢



下面,只要p不为空(p!=NULL)

即p有所指向,那么就打印p所指向的车厢的里面的data值。

然后,p再指向下一节车厢(p=p->pNext)



循环上面步骤,直到p指向最后一节车厢



再循环,p指向第4节车厢。

唉?第4节车厢没了!

那么p==NULL了,退出while循环。至此,循环遍历完毕。

完整代码如下:

//判断链表是否为空
int isEmpty(PNODE pHead)
{
if(pHead->pNext==NULL)
{
return 1;
}
else
{
return 0;
}
}
//遍历链表
void traverseList(PNODE pHead)
{
if(isEmpty(pHead))
{
printf("链表为空\n");
}
else
{
PNODE p=pHead->pNext; while(p!=NULL) { printf("%d ",p->data); p=p->pNext; }
free(p);
}
}


3、删除链表

假设p指向第1节车厢,q指向第2节车厢。

比如我们要删除第2节车厢。

如图:



即:

p->pNext=q->pNext;(p指向第1节车厢,q指向第2节车厢)

使第1节车厢的pNext指向第3节车厢,就删除了第2节车厢。

整体代码为:

//删除任意位置的元素
void deleteList(PNODE pHead,int pos)
{
if(isEmpty(pHead))
{
printf("链表为空,不可删除\n");
}
else
{
PNODE p=pHead->pNext;
//注意这里的i=2(因为p指向的是要删除车厢的前一节车厢)
int i=2;
while(p!=NULL && i!=pos)
{
p=p->pNext;
i++;
}
PNODE q=p->pNext;
p->pNext=q->pNext;
free(q);
}
}


三、整体代码

#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node * pNext;
}NODE,*PNODE;
//创建链表
PNODE createList()
{
int i,val,n;
PNODE pHead=(PNODE)malloc(sizeof(NODE));
PNODE pTail=pHead;
pHead->pNext=NULL;
printf("请输入链表长度:");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("请输入第%d个数值\n",i+1);
scanf("%d",&val);
PNODE pNew=(PNODE)malloc(sizeof(NODE));
pNew->data=val;
pTail->pNext=pNew;
pTail=pNew;
pNew->pNext=NULL;
}
return pHead;
}
//判断链表是否为空
int isEmpty(PNODE pHead)
{
if(pHead->pNext==NULL)
{
return 1;
}
else
{
return 0;
}
}
//遍历链表
void traverseList(PNODE pHead)
{
if(isEmpty(pHead))
{
printf("链表为空\n");
}
else
{
PNODE p=pHead->pNext; while(p!=NULL) { printf("%d ",p->data); p=p->pNext; }
free(p);
}
}
//删除任意位置的元素
void deleteList(PNODE pHead,int pos)
{
if(isEmpty(pHead))
{
printf("链表为空,不可删除\n");
}
else
{
PNODE p=pHead->pNext;
int i=2;
while(p!=NULL && i!=pos)
{
p=p->pNext;
i++;
}
PNODE q=p->pNext;
p->pNext=q->pNext;
free(q);
}
}
int main()
{
PNODE pHead=createList();
bubbleSort(pHead);
traverseList(pHead);
return 0;
}



四、总结

从以上实现可以看出,链表的删除非常简便,但是查找很慢,很繁琐,需要从pHead一个个查起。

优点:插入删除简单,花费时间短。空间没有限制。

缺点:查询慢,比数组多一个pNext域,所占总空间大。

线性结构有数组和链表。数组和链表各有优缺点。没有哪一个最好。也就是没有最好,只有更好,看哪个更适合你的需求,就选择哪个结构。

本人初学,很多问题不甚明了。

如有错误或不当之处,敬请您不吝指正,

如果有问题需要探讨,烦请留言回复。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  链表