1.带头节点的单链表。
//结点定义:
typedef int DataType; //定义抽象数据类型
//节点的结构体
typedef struct Node
{
DataType data; //节点的数据域
struct Node *next; //节点的指针域
} SLNode;
//初始化ListInitiate(head)
void ListInitiate(SLNode **head)
{
*head = (SLNode *)malloc(sizeof(SLNode));
(*head)->next = NULL;
}
这里参数使用了指针的指针,是为了使主函数里的头指针指向这个函数开辟的空间节点,使用指针的指针保存的是头指针的地址,那么对这个地来址里面值的改变,就是对头指针里面值得改变,这里需要使用指针的指针,来进行对实参值的改变。
//求当前数据元素个数ListLength(head)
int ListLength(SLNode *head)
{
SLNode *p = head;
int size = 0;
while (p->next != NULL)
{
p = p->next;
size++;
}
return size;
}
求当前数据元素个数的操作:先定义一个指向头结点的指针*p=head;
,通过移动指针的指向,同时size++,达到遍历链表的目的,当指针指向空的时候,链表遍历结束,此时size就是当前数据元素的个数。
//插入ListInsert(head, i, x)
int ListInsert(SLNode *head, int i, DataType x)
{
SLNode *p, *q;
int j;
p = head;
j = -1;
while (p->next != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (j != i - 1)
{
printf("插入位置参数错!");
return 0;
}
q = (SLNode *)malloc(sizeof(SLNode));
q->data = x;
q->next = p->next;
p->next = q;
return 1;
}
说明:①要在带头结点的单链表第i(0 ≤ i ≤ size)个结点前插入一个存放数据元素x的结点,首先要在单链表中寻找到第i-1个结点并由指针p指示,然后动态申请一个结点存储空间并由指针q指示,并把数据元素x的值赋予新结点的数据元素域(即q->data = x),最后修改新结点的指针域指向ai结点(即q->next = p->next),并修改ai-1结点的指针域指向新结点q(即p->next = q)。
②循环条件由两个子条件逻辑与组成,其中子条件p->next != NULL保证指针所指结点存在,子条件j < i - 1保证最终让指针p指向ai-1结点。
//删除ListDelete(head, i, x)
int ListDelete(SLNode *head, int i, DataType *x)
{
SLNode *p, *s;
int j;
p = head;
j = -1;
while (p->next != NULL && p->next->next != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (j != i - 1)
{
printf("插入位置参数错!");
return 0;
}
s = p->next;
*x = s->data;
p->next = p->next->next;
free(s);
return 1;
}
说明:要在带头结点的单链表中删除第i(0 ≤ i ≤ size - 1)个结点,首先要在单链表中寻找到第i-1个结点并由指针p指示,然后让指针s指向ai结点(即s = p->next),并把数据元素ai的值赋予x(即*x = s->data),最后把ai结点脱链(即p->next = p->next->next),并动态释放ai结点的存储空间(即free(s))。删除过程上图所示。图中的①对应算法中的删除语句。
//取数据元素ListGet(head, i, x)
int ListGet(SLNode *head, int i, DataType *x)
{
SLNode *p;
int j;
p = head;
j = -1;
while (p->next != NULL && j < i)
{
p = p->next;
j++;
}
if (j != i)
{
printf("取元素位置参数错!");
return 0;
}
*x = p->data;
return 1;
}
//撤消单链表Destroy(head)
void Destroy(SLNode **head)
{
SLNode *p, *p1;
p = *head;
while (p != NULL)
{
p1 = p;
p = p->next;
free(p1);
}
*head = NULL;
}
单链表求数据元素个数操作的时间复杂度为O(n)。
主要优点是不需要预先确定数据元素的最大个数,插入和删除操作不需要移动数据元素;
主要缺点是查找数据元素时需要顺序进行,不能像顺序表那样随机查找任意一个数据元素。另外,每个结点中要有一个指针域,因此空间单元利用率不高。而且单链表操作的算法也较复杂。