线性表(List):零个或多个数据元素的有限序列。线性表的抽象数据类型。
线性表的顺序存储:
优点:无须为表示表中元素的逻辑关系而额外的存储空间,可以快速的取表中任意位置的元素。
缺点:插入和删除操作需要转移大量元素,线性表的长度较大时,难以确定存储空间的容量, 造成存储空间的“碎片”。
线性表的链式存储:
为了表示每一个数据元素a1与其直接后级数据元素ai+1之间的逻辑关系,对数据元素a1来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信号(即直接后继的存储位置)。存储数据元素信息的域叫做数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称为指针或链。这两部分组成数据元素ai的存储影像,称为结点(Node)
其中头指针和头结点的区别:
1,头指针是指向链表的第一个结点的指针,若链表有都结点,则指向头结点的指针。头指针具有标示作用,所以常用头指针冠以链表的名字。无论链表是否为空,头指针均不为空,头指针是链表的必要条件。
2,头结点是为了操作的统一和方便设置的,放在头一个元素的结点之前,其数据域一般无意义。有了头结点,对其在第一元素位置前插入删除擦偶偶与其他结点的操作统一。头结点不是链表的必须要素。
带有头结点的指针;
空链表:
C语言中用结构指针表示结点:
typedef struct Node
{
int data;
struct Node *next;
}Node, *pNode,*LinkList;
其中单链表的抽象数据结构即操作有:
void InitList(LinkList *list);//初始化操作,建立空的单链表
void ClearList(LinkList *list);//清空单链表。
void ListInsert(LinkList *list,int i, int e);//单链表第i个位置后面插入变量e
void DestoryList(LinkList *list);//销毁链表
bool ListEmpty(LinkList list);//判断单链表是否为空,为空返回真
void GetElem(LinkList, int &e, int i);//将单链表中第i个位置的值返回给变量e
void ListDelete(LinkList *list, int i, int &e);//删除单链表表第i个位置元素
void ListTraverse(LinkList list);//遍历线性表
int ListLength(LinkList list);//返回线性表的长度
void Recursion(LinkList list);//递归逆序输出单链表
各种函数的实现源代码:
void InitList(LinkList *list)
{
*list = (LinkList)malloc(sizeof(Node));
(*list)->next = NULL;
(*list)->data = 0;
}
void ListInsert(LinkList *list, int i , int e)//第i个元素后面插入e
{
LinkList p = *list;
if( i == 0)
{
pNode q = (LinkList)malloc(sizeof(Node));
q->next = NULL;
q->data = e;
p->next = q;
}
else
{
pNode p = (*list)->next;
int j = 1;
while( p && i > j)
{
p = p->next;
++j;
}
pNode q = (LinkList)malloc(sizeof(Node));
q->next = p->next;
q->data = e;
p->next = q;
}
}
void ListTraverse(LinkList list)
{
pNode p = list;
if(p != NULL)
{
p = p->next;
}
else
{
return;
}
while(p)
{
printf("%d\t", p->data);
p = p->next;
}
}
void Recursion(LinkList list)//递归的方法逆序输出链表
{
if(NULL==list)
{
return;
}
if(list->next!=NULL)
{
Recursion(list->next);
}
printf("%d\t",list->data);
}
bool ListEmpty(LinkList list)
{
pNode p = list;
if(NULL == list->next)
return true;
else
return false;
}
void GetElem(LinkList list, int &e, int i)
{
pNode p = list;
if( i < 0 || i > ListLength(list))
return ;
p = p->next;
int j = 1;
while( j < i)
{
p = p->next;
j++;
}
e = p->data;
}
void ListDelete(LinkList *list, int i, int &e)
{
pNode p = *list;
if( i < 0 || i > ListLength(*list))
return ;
pNode q = p;
p = q->next;
int j = 1;
while( j < i )
{ q = p;
p = p->next;
j++;
}
p->data = e;
q->next = p->next;
free(p);
}
int ListLength(LinkList list)
{
pNode p = list;
int i = 0;
p = p->next;
while(p)
{
p = p->next;
i++;
}
return i;
}
void ClearList (LinkList *list)
{
pNode p = *list;
if( p != NULL)
p = p->next;
pNode q;
while( p )
{
q = p;
p = p->next;
free(q);
}
}
void DestoryList(LinkList *list)
{
pNode p = *list;
if( p != NULL)
p = p->next;
pNode q;
while( p )
{
q = p;
p = p->next;
free(q);
}
free(*list);
}
测试函数源代码:
int main()
{
LinkList list;
InitList(&list);
ListInsert(&list, 0, 1);
ListInsert(&list, 1, 2);
ListInsert(&list, 2, 3);
ListInsert(&list, 1, 4);
ListInsert(&list, 1, 5);
ListInsert(&list, 5, 6);
ListInsert(&list, 6, 7);
ListInsert(&list, 7, 8);
ListInsert(&list, 8, 9);
ListInsert(&list, 9, 10);
printf("\n递归调用函数Reversion:\n");
LinkList p = list->next;
Recursion(p);
printf("\n遍历链表ListTranverse:\n");
ListTraverse(list);
int j = ListLength(list);
printf("\n链表的长度ListLength:%d\t",j);
int e;
GetElem(list, e, 3);
printf("取链表特定的元素GetElem : %d\n",e);
ListDelete(&list, 1, e);
printf("\n删除链表中特定位置的元素:%d\n", e);
ListTraverse(list);
ClearList (&list);
printf("\n链表清空ClearList: \n");
ListInsert(&list, 0, 1);
ListInsert(&list, 1, 2);
ListInsert(&list, 2, 3);
ListTraverse(list);
DestoryList(&list);
return 0;
}
参考: 大话数据结构,数据结构(C语言版)严蔚敏版