上一篇我们讲到了线性表,线性表就是数据元素都一一对应,除只有唯一的前驱,唯一的后继。
线性表存储结构分为顺序存储、链式存储。
顺序存储的优点:
顺序存储的缺点:
链表就是典型的链式存储,将线性表L = (a0,a1,a2,........an-1)中个元素分布在存储器的不同存储块,成为结点(Node),通过地址或指针建立他们之间的练习,所得到的存储结构为链表结构。表中元素ai的结点形式如下:
其中,结点的data域存放数据元素ai,而next域是一个指针,指向ai的直接后继a(i+1)所在的结点。于是,线性表L=(a0,a1,......an-1)的结构如图:
一、节点类型描述:
typedef struct node_t
{
data_t data; //节点的数据域
struct node_t *next;//节点的后继指针域
}linknode_t,*linklist_t;
也可这样表示:
struct node_t
{
data_t data;
struct node_t *next;
}
typedef struct node_t linknode_t;
typedef struct node_t *linklist_t;
若说明
linknode_t A;
linklist_t p = &A;
则结构变量A为所描述的节点,而指针变量P为指向此类型节点的指针(p的值为节点的地址);
这样看来 linknode_t linklist_t 的作用是一样的,那为什么我们要定义两个数据类型(同一种)呢?主要为了代码的可读性,我们要求标识符要望文识义,便于理解;
1、linknode_t *pnode 指向一个节点;
2、linklist_t list 指向一个整体
二、头结点 head
我们在前篇提到的顺序存储线性表,如何表达一个空表{ },是通过list->last = -1来表现的,所谓的空表就是数据域为NULL,而我们的链表有数据域和指针域,我们如何表现空链表呢?这时,就引入了头结点的概念,头结点和其他节点数据类型一样,只是数据域为NULL,head->next = NULL,下面我们看一个创建空链表的函数,如何利用头结点来创建一个空链表:
linklist_t CreateEmptyLinklist()
{
linklist_t list;
list = (linklist_t)malloc(sizeof(linknode_t));
if (NULL != list) {
list->next = NULL;
}
return list;
}
只要头结点,链表就还在!
三、链表基本运算的相关算法
链表的运算除了上面的创建空链表,还有数据的插入,删除,查找等函数,链表的运算有各种实现方法,如何写出一个高效的&#x