链表的理解与实现[数据结构]
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域,所占总空间大。
线性结构有数组和链表。数组和链表各有优缺点。没有哪一个最好。也就是没有最好,只有更好,看哪个更适合你的需求,就选择哪个结构。
本人初学,很多问题不甚明了。
如有错误或不当之处,敬请您不吝指正,
如果有问题需要探讨,烦请留言回复。
相关文章推荐
- [C/C++]反转链表
- C#实现基于链表的内存记事本实例
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- C++实现简单的学生管理系统
- Linux内核链表实现过程
- C++链表倒序实现方法
- C#通过链表实现队列的方法
- C#实现的简单链表类实例
- 找出链表倒数第n个节点元素的二个方法
- Java数据结构之简单链表的定义与实现方法示例
- C语言单循环链表的表示与实现实例详解
- C++实现的链表类实例
- PHP小教程之实现链表
- C语言双向链表的表示与实现实例详解
- js链表操作(实例讲解)
- C语言实现输出链表中倒数第k个节点
- C++语言实现线性表之链表实例
- STL list链表的用法详细解析
- C语言创建链表错误之通过指针参数申请动态内存实例分析
- php链表用法实例分析