单向链表

来源:互联网 发布:大数据的发展趋势 编辑:程序博客网 时间:2024/06/08 16:04

 

                       单向链表
1 这里我重点总结一下带头结点的单向链表,说实在话,这个带头结点这句话算是迷惑了我很长时间,我们可以把它理解成为结点,也可以不把它理解为结点。只不过是我们定义了一个结构体而已,里面包含了整个链表的属性信息,及一个头指针和一个尾指针。头指针指向第一个结点,尾指针指向最后一个结点。
其中链表的属性信息里面可以包含有链表的长度。当然我们里面可以什么都不存储。下面我们来看一下单向链表在内存中的存储。

2000:1000
2000:1010
2000:1020
2000:1030
2000:1040
2000:1050
2000:1060
...
2000:4000
头指针2000:1006
2000:1030
a3
2000:1040
a6
NULL
a1
2000:1060
a4
2000:1050
a5
2000:1020
a2
2000:1010
数据域
指针域
 
 
//头指针
//第二个结点
//最后一个结点
//第一个结点
//第三个结点
//第四个结点
//第二个结点

 
由上面例子我们可以很清楚的明白单向链表和顺序链表的区别。即单向链表在内存中是离散存储(非顺序存储)的。这个特点可是说是单链表的一个优点,因为他这种特性使它的插入,删除操作变得异常方便。即只需改变指针的指向就OK,无需移动元素的位置。然而这一优点也给它带来了一个缺点。即无法实现对数据的直接存储。
下面我们一起定义一个带头结点的单向链表。
我们首先定义普通的结点:
typedef struct Node
{
 ElemType data; //结点里存的数据
 Struct Node *next;//指向下一个结点的指针
}Node,*Link;
一个普通的头结点已经定义完成。大家不要被我的定义所迷惑,我只定义了一个数据元素,其实一个结点里可以存储的元素不止一个,我们还可以给它添加元素,甚至你可以在里面再添加一个struct或是union也无妨。根据需要而定。
下面再来定义头结点:
typedef struct SqList
{
 Link head,tail;
 int length;
}LinkList;
好的,头结点已经定义完成。这里面的尾指针可要可不要,根据个人喜好吧,不过若我们加上尾指,对我们在遍历链表时百利而无一害。如:
我们可以利用这样的控制语句:
LinkList La;
Link q = La.head;
while (q <= La.tail)
{
}
是不是很方便啊。程序的易读性也加强了。当然如果没有尾指针,我们一样可以遍历数组,不过我们得这样了:
while (q->next != NULL)
{
}
while (q != NULL)
{
}
根据具体需要选择吧。
2 链表的操作
     初始化
Status InitList(LinkList &La)
{
   La.head = (Link)malloc(sizeof(SqList));
   La.head = La.tail = NULL;
   La.length = 0;
   return OK;
}
     插入操作
对于单向链表的插入操作我想比栈的或是顺序链表的简单多了。至少他无需考虑是否空间已满的问题。因为他在每次进行插入操作时都需定义一个新结点并为它分配空间然后插入到相应的位置即可。对于带头指针和尾指针的单向链表在插入的时候需要注意一下几点:
若插入的是第一个位置,即La.length == 0时,这时我们需要修改头指针的指向。若我们插入的位置是最后,我们需要修改尾指针的指向。
Status ListInsert(LinkList &La,int i,ElemType e)
{
   if (0 == La.length)
   {
     Link p = (Link)malloc(sizeof(Node));
     p->data = e;
     La.head ->next = p;
     p->next = NULL;
     La.tail = p;
La.length++;
   return Ok;
}
else if (i == La.length+1)
{
 Link t = (Link)malloc(sizeof(Node));
 t->data = e;
 La.tail ->next = t;
 t->next = NULL;
 La.tail = t;
 return OK;
}
else
{
   Link q = La.head; int j = 0;
while(q && j < i-1)
{
     q = q->next;
     j++;
}
if (!q || j > i-1)
return ERROR;
Link s = (Link)malloc(sizeof(Node));
s->data = e;
s->next = q->next;
q->next = s;
return OK;
}
}
     删除操作
在带有头指针和尾指针的单向链表在删除的时候和插入的时候一样要小心。如当我们删除的是第一个结点时,我们要修改头指针的指向,若我们删除的是最后一个结点时我们要修改尾指针的指向。
Status ListDelete(LinkList &La,int i,ElemType &e)
{
   if(1 == i)
   {
     Link p = La.head;
     La.head = p->next;
     free(p);
     return OK;
   }
   else if (La.length == i)
   {
     Link q = La.head;
     while(q->next->next != NULL)
     {
         q = q->next;
     }
     Link s = q->next;
     La.tail = q;
     free(s);
    return OK;
   }
else
{
 Link t = La.head;
 int j = 0;
 while (t && j < i-1)
 {
t = t->next;
++j;
 }
 if (t->next || j > i-1)
 return ERROR;
 Link h = t->next;
 t->next = h->next;
 e = h->data;
 free(h);
 return OK;
}
}

链表的初始化函数感觉不对。。请大家指正。其他若有什么不对的欢迎大家来讨论哈。。一起学习,一起进步!