码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构与算法分析—— 1、链表

时间:2015-08-13 01:01:37      阅读:296      评论:0      收藏:0      [点我收藏+]

标签:

  链表是一种最简单的数据结构,当我们在使用数组存储数据的时候,频繁的插入和删除会损耗大量的性能,而链表正是一种适合频繁插入删除操作的线性数据结构。

  有关链表的详细介绍可以看这里,通俗的来说,链表就是由一些节点构成,每个节点有一个指针,这个指针保存着下一个节点的位置。因此,链表就是由指针将这些物理上没有逻辑关系的节点连接了起来,构成一个有关系的线性表。

  我们先来看“单链表”,在C语言当中,具有封装能力的数据类型是结构体。因此,我们用一个结构体来表示一个节点。定义如下:

1 struct Node{
2      ElementType Element;
3      struct Node * Next; 
4 };

   在这里,我们假设元素的类型为 int ,于是这样定义:

1 typedef int ElementType;

  对于一个链表,它的基本操作有:判断链表是否为空、当前元素是否为最后一个、查找一个元素、插入一个元素、删除一个元素、删除整个表等。所以我们有如下声明:

1 int IsEmpty(List L);
2 int IsLast(Position P);
3 Position Find(ElementType X, List L);
4 void Delete(ElementType X, List L);
5 void Insert(ElementType X, Position P);
6 void DeleteList(List L);

   对了,忘了类型定义了。使用类型定义可以让代码看起来更简洁,也更容易理解。Position 和 List 类型都是“指向Node的指针”,不过我们用 List 来表示头结点,Position 来表示任意节点。这样,程序一目了然。

1 typedef struct Node * PtrToNode;
2 typedef PtrToNode List;
3 typedef PtrToNode Position;

   接下来就是实现了,我们先从判断链表是否为空开始。我们传入头指针,只需要判断头结点的 Next 指针是否为 NULL 即可。若 Next 为 NULL,说明链表只有头结点,为空。

1 int 
2 IsEmpty(List L) {
3     return L->Next == NULL;
4 }

   判断当前元素是否为最后一个元素的方式也与此类似,因为当一个结点处于末尾时,它的 Next 指针为 NULL。

1 int 
2 IsLast(Position P) {
3     return P->Next == NULL;
4 }

   然后我把接下来的几个函数的实现全部放出来,都是很容易理解的。

 1 Position 
 2 Find(ElementType X, List L) {  
 3     Position P;
 4     P = L->Next;
 5     while (P != NULL && P->Element != X) {
 6         P = P-Next;    
 7     }
 8     return P;
 9 }
10 
11 void 
12 Insert(ElementType X, Position P) {
13     Position temp;
14     temp = malloc(sizeof(struct Node));
15     
16     temp->Element = X;
17     temp->Next = P->Next;
18     P->Next = temp;
19 }
20 
21 void 
22 DeleteList(List L) {
23     Position P, temp;
24     P = L->Next;
25     L-Next = NULL;
26     while (P != NULL) {
27         temp = P->Next;
28         free(P);
29         P = temp;
30     }
31 }
32 
33 void
34 Delete(ElementType X, List L) {
35     Position P, temp;
36     P = FindPrevious(X,L); //找到X的前一个元素
37     if (!IsLast(P,L)) {
38          temp = P->Next;
39          P-Next = temp->Next;
40         free(temp);
41     }
42 }

   我们发现上面有个 FindPrevious 函数用来找到当前元素的上一个元素,这个函数的出现是我们之前没预料到的。然而在删除操作当中我们发现需要这样一个函数,所以我们也声明这样一个函数,先不去考虑它的具体实现(这就是抽象)。事实上它的实现也是很简单的,不过我们会想到,既然可以用指针保存下一个结点,那为什么不用一个指针保存上一个结点呢?于是,双向链表就这么诞生了。

1 struct Node{
2     ElementType Element;
3     struct Node * Next; 
4     struct Node * Prev; 
5 };

  现在删除操作可以这样:

1 P->Prev->Next = P->Next; //P是指向要删除结点的指针
2 p->Next->Prev = P->Prev;
3 free(P);

  当链表的头尾相连时,这个链表就成了循环链表。在C#当中有个 LinkedList 类实现了 双向循环链表 ,文档和源码可以看这里这里。真是壮哉我大微软,文档资料应有尽有。

  写到这里,应该算写完了吧。还是没有达到下笔如有神的状态,我想应该是和分享的对象有关系。这文章要给哪一类读者看呢?其实是给我自己看的,那就这样吧,这一系列文章将纯粹是我为了总结而作的记录,没有读者对象。坑已经给自己挖了,后面还有很多较深的知识点,我会填坑的。

  下一篇应该是“栈”,而且我会讲解一个栈的实例。

(完)

   

数据结构与算法分析—— 1、链表

标签:

原文地址:http://www.cnblogs.com/huangmingchuan/p/4720328.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!