链表
链表是一种动态的数据结构,它是动态进行存储分配的一种结构。通常,对于大批的数据可以采用数组的方式保存,但是用数据保存存在明显的问题。第一,数组需要在使用之前确定大小,一旦数据超过了数组的容量,就会发生数组溢出,分配的数据空间过大,则会造成浪费;如果使用动态数组,效率太低。第二,在数组中删除、插入数据需要移动数组中的数据,效率也比较低。链表正是针对数组的这些缺点而设计的一种存储数据的动态数据结构。
在链表中,所有数据元素都分别保存在一个具有相同数据结构的节点中,节点是链表的基本存储单位,一个节点与一个数据元素对应。每个节点在内存中使用一块连续的存储空间,每个节点也可以使用不连续的存储空间,节点之间通过指针连在一起,连接节点的指针也称为链。
节点的存储结构在内存空间中通常分为两个部分:信息数据部分(数据域)和连接节点的指针(指针域)。节点定义采用结构体类型,一般形式为:
struct node
{
datatype data; /*信息数据,根据实际数据定义*/
struct node *link; /*指向节点node的指针*/
}
节点的数据类型名称是struct node;data是实际需要的结构成员分量;datatype是实际分量所需要的数据类型;link是一个指向struct node类型的结构指针,即link指向的对象是一个同样类型的数据节点,它是一个动态的指针,用来存放一个节点的地址。通过link指针,一个个节点被依次连接起来,形成链表。
一个链表一般由头指针、表头节点和数据节点三部分组成。
建立动态单向链表:
建立链表首先要定义一个包含数据域和指针域的结构类型,然后建立指向表头节点的头指针head,最后通过malloc函数动态申请一块内存作为表头节点。
typedef struct node
{
int data; /*数据域*/
struct node *link; /*指针域*/
} NODE; /*定义节点*/
NODE *head; /*定义头指针head*/
定义结构类型和头节点之后,我们要建立不包含数据的表头节点,可以按下列语句进行操作:
NODE *p; /*定义一个指向节点的指针变量p*/
p = (NODE*)malloc(sizeof(NODE)); /*申请表头节点*/
p->link = NULL; /*将表头节点的link置为NULL*/
head = p; /*head指向表头节点p*/
此时链表中只有一个表头节点,没有数据节点,所以称为空链表。
为了在链表中保存数据,可以从表头位置将数据节点插入到链表中,例如,插入一个数据节点:
p = (NODE*)malloc(sizeof(NODE)); /*申请一个数据节点*/
gets(p->data); /*输入一个新的数据*/
p->link = head->link; /*建立链接关系,将表头节点的link存入p的link中*/
head->link = p; /*将数据节点插在表头节点之后成为第一个数据节点*/
根据上面的链表建立过程,可以写出函数create建立有n个数据节点的链表,如下:
create(NODE *head,int n)
{
NODE *P;
for(;n>0;n--)
{
p = (NODE*)malloc(sizeof(NODE));
if(p == NULL)
exit(0);
gets(p->data);
p->link = head->link;
head->link = p;
}
}
单向链表的输出:
将单向链表中各节点依次输出,首先要知道链表第一个节点的地址,然后设一个指针变量p,先指向第一个节点,输出p所指的节点,然后使p后移一个节点再输出,直到链表的尾节点。
void print(NODE *head)
{
NODE *p;
p = head;
if(head != NULL)
do
{
printf("%d/n",p->data);
p = p->link;
}while(p != NULL)
}
对单向链表的删除操作:
要删除链表中第i个节点的基本算法如下:
1.定位第i-1个节点。指针q指向第i-1个节点,指针p指向被删除的节点。
2.摘链。q->link = p->link.
3.释放p节点。free(p).
程序如下:
delete_node(NODE *head,int i)
{
NODE *q,*p;
int n;
for(n=0,q=head;(n<i-1)&&(q->link!=NULL);++n)
q = q->link; /*定位第i-1个节点*/
if((i>0)&&(q->link!=NULL))
{
p = q->link; /*p指向被删除的第i个节点*/
q->link = p->link; /*摘链*/
free(p); /*释放p节点*/
}
}
对单向链表的插入操作:
在链表的第i个节点的后面插入一个新结点的基本算法如下:
1.定位第i个节点。让指针q指向第i个节点,指针p指向需要插入的节点。
2.链接后面指针。p->link = q->link
3.链接前面指针。q->link = p
程序如下:
insert_node(NODE *head,NODE *p,int i)
{
NODE *q;
int n=0;
for(q=head;(n<i)&&(q->link!=NULL);++n)
q = q->link; /*定位第i个节点*/
p->link = q->link; /*链接后面指针*/
q->link = p; /*链接前面指针*/
}