一、链表的定义
链表是一种物理存储单元上非连续、非顺序的存储结,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表是由一系列结点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。
二、链表的存储结构
链表的存储结构是链式存储,链式存储的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素与其直接后继数据元素之间的逻辑关系,对数据元素来说,出来存储其本身的数据元素的信息之外,还需存储一个直接后继的的信息,也就是直接后继的存储位置。
它的结构图就像下面一样
三、单链表的操作
单链表的操作同样有构造空表,销毁链表,增加元素,删除元素,逆置,排序……我们也通过一个例子来说明它所有的操作:
#include<stdio.h>
#include<malloc.h>
typedef struct NODELIST
{
int data;
struct NODELIST *next;
}nodelist;
nodelist *createList(int a) //创建一个有a个元素的链表,输入其值
{
nodelist *head, *p, *q;
head = (nodelist *)malloc(sizeof(nodelist));
p = head;
for(int i=1;i<=a;i++)
{
q = (nodelist *)malloc(sizeof(nodelist));
p->next = q;
q->data = i;
p = q;
}
p->next = NULL;
return head;
}
void destroyNodeList(nodelist *head) //销毁此链表
{
if(head == NULL)
return;
if(head->next == NULL)
{
free(head);
head = NULL;
return;
}
nodelist *p = head->next;
while(p!=NULL)
{
nodelist *q = p;
p = p->next;
free(q);
}
free(head);
head = NULL;
}
void Print(nodelist *head) //遍历整个链表,并且打印其数据域的元素
{
nodelist *p;
p = head->next;
while(p)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
void InsertList(nodelist *head, int i, int data)//在第i个位置之前插入元素data
{
int j = i-1;
nodelist *p, *q;
p = head;
while(j--)
p = p->next;
q = (nodelist *)malloc(sizeof(nodelist));
q->next = p->next;
q->data = data;
p->next = q;
}
void InsertLast(nodelist *head, int data)//在链表尾部插入一个元素data
{
nodelist *p, *q;
p = head;
while(p->next)
p = p->next;
q = (nodelist *)malloc(sizeof(nodelist));
q->data = data;
p->next = q;
q->next = NULL;
}
void deleteList(nodelist *head, int data) //删除元素 data
{
nodelist *p, *q = head;
p = head->next;
while(p)
{
if(p->data == data)
break;
p = p->next;
q = q->next;
}
q->next = p->next;
free(p);
}
void reverseList(nodelist *head) //链表逆序
{
if(head == NULL || head->next == NULL)
return;
nodelist *p = head->next;
nodelist *q = p->next;
nodelist *t = NULL;
while(q!=NULL)
{
t = q->next;
q->next = p;
p = q;
q = t;
}
(head->next)->next = NULL;
head->next = p;
}
void sortlist(nodelist *head) //排序(降序)
{
nodelist *p, *q, *t;
if(head->next == NULL || head == NULL)
return;
p = head;
q = p->next;
t = p->next;
for(;q!=NULL;q = q->next)
for(t=q->next;t!=NULL;t=t->next)
{
if(q->data > t->data)
{
int a = q->data;
q->data = t->data;
t->data = a;
}
}
}
int main()
{
int a;
NODELIST *head;
scanf("%d", &a);
head = createList(a);
InsertList(head, 3, 0);
Print(head);
InsertLast(head, 5);
Print(head);
deleteList(head, 3);
Print(head);
reverseList(head);
Print(head);
sortlist(head);
Print(head);
destroyNodeList(head);
return 0;
}
链表的操作就是我上面写的程序。那么我们在什么时候选择使用链表呢,链表给我们带来了什么好处》
链表的优点如下:
我们再插入删除元素的时候,不需要移动大量的元素,效率很高;链表的存储密度低,对内存的利用率很高;使用链表可以很方便的扩展所占空间的大小。
链表的缺点如下:
我们只能通过指针去顺序访问元素,如果要进行读取元素,它的复杂度是O(n),效率很低。
所以我们如果要进行大量的删除和插入元素的操作,而读取元素的操作不多的情况下,我们使用链表是一个很好的选择!