1. 链表
1.1 简介
链表包含两种,或者说三种,即单链表, 多链表, 循环链表。其中单链表只表示的next的关系,而多链表即包含了next, 又包含了pre;循环链表则是单链表与多链表的衍生链表,即头尾相链,构成循环。循环链表又分为单循环链表及多循环链表。’
1.2 概念
- 头指针:链表中第一个结点的存储位置叫做头指针。整个链表的存取从头指针开始。
- 最后一个结点的指针:后继不存在,应为空,通常用NULL或“^”表示是
- 头结点:为方便对链表进行操作,在单链表的第一个结点前附设一个结点,称为头结点。头结点的数据域可以不存储任何信息,也可以存储如线性表的长度等附加信息,头结点的指针域存储第一个结点的指针
- 头指针作用:就是存放数组地址,也即是链表地址。
- 头结点好处:首先它是链表中的元素,是个有效的结点;对带头结点的链表,在链表中的任何位置插入或删除结点,要做的就是修改前一结点的指针域,因为任何结点都有前驱结点;如果链表中没有头结点,则首元素结点没有前驱,那么在其前插入或删除首元素结点时候,操作比较麻烦;对带头结点的链表,表头指针是指向头结点的非空指针,因为空表和非空表的处理是一样的。
注:头指针–>(头结点)–>开始结点(第一个结点) - 一个单链表可以由其头指针唯一确定,一般用其头指针来命名单链表
- 不论链表是否为空,头指针总是非空
- 单链表的头指针指向头结点。
- 头结点的指针域存储指向第一结点的指针(即第一个元素结点的存储位置)
- 若线性表为空表,则头结点的指针域为空。
1.3 单链表
1.3.1. 创建单链表
- 头插法
void CreateListHead(LinkList *L,int n)//创建链表(头插法)
{
LinkList p;
int i;
srand(time(NULL));//初始化随机数种子
*L = (LinkList)malloc(sizeof(Node));
(*L)->data = -1;
(*L)->next = NULL;//创建空链表
for(i=0;i<n;i++)
{
p = (LinkList)malloc(sizeof(Node));
#if 0
p->next = (*L)->next;
(*L)->next = p;
#else
tmp = (*L)->next;
(*L)->next = p;
p->next = tmp;
#endif
}
}
L地址:0x0x556ee693f6b0 -1
L->next地址:0x0x556ee693f6b8
L->next地址:0x(nil)
p地址:0x0x556ee693f6d0 27
p->next地址:0x0x556ee693f6d8
p->next地址:0x(nil)
L地址:0x0x556ee693f6b0 -1
L->next地址:0x0x556ee693f6b8
L->next地址:0x0x556ee693f6d0
p地址:0x0x556ee693f6f0 3
p->next地址:0x0x556ee693f6f8
p->next地址:0x(nil)
L地址:0x0x556ee693f6b0 -1
L->next地址:0x0x556ee693f6b8
L->next地址:0x0x556ee693f6f0
p地址:0x0x556ee693f710 57
p->next地址:0x0x556ee693f718
p->next地址:0x(nil)
L地址:0x0x556ee693f6b0 -1
L->next地址:0x0x556ee693f6b8
L->next地址:0x0x556ee693f710
-1 27 3 57
- 尾插法
void CreateListTail(LinkList *L,int n)//创建链表(尾插法)
{
LinkList p,r;
int i;
srand(time(NULL));
*L = (LinkList)malloc(sizeof(Node));
(*L)->data = -1;
r = *L;
for(i=0;i<n;i++)
{
p = (LinkList)malloc(sizeof(Node));
p->data = rand()%100+1;
r->next = p;
r = p;
}
r->next = NULL;
}
1.3.1. 插入新节点
int ListInsert(LinkList *L,int i,data_t e)//插入新节点,使其成为第i个节点
{
int j;
LinkList p,s;
p=*L;
j=1;
while(p && j<i)
{
p=p->next;
j++;
}
if(!p || j>i)
{
printf("第%d个位置不存在!\n",i);
return ERROR;
}
s=(LinkList)malloc(sizeof(Node));
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
1.3.2. 遍历链表
int GetElem(LinkList L,int i,data_t *data)//读取单链表的第i个元素
{
int j;
LinkList p;
p = L;
j = 1;
while(p && j<i)
{
p = p->next;//让p指向下一个节点
j++;
}
if(!p || j>i)
{
printf("第%d个位置不存在!\n",i);
return ERROR;
}
*data = p->data;
return OK;
}
1.3.2. 删除链表
int ListDelete(LinkList *L,int i,data_t *e)//删除第i个位置节点,数据由e获得
{
int j;
LinkList p,q;
p=*L;
j=1;
while(p->next && j<i)
{
p=p->next;
j++;
}
if(!(p->next) || j>i)
{
printf("第%d个位置不存在!\n",i);
return ERROR;
}
q=p->next;
p->next=q->next;
*e=q->data;
free(q);
return OK;
}
1.3.3. 销毁链表
int ClearList(LinkList *L)//销毁链表
{
LinkList p,q;
p=(*L)->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
(*L)->next=NULL;
return OK;
}
1.3.4. 单链表反序
int ListReverse(LinkList L)//练习1:单链表反序
{
if(!L)
{
printf("单链表反序操作错误!\n");
return ERROR;
}
LinkList p,q;
p=L->next;//记录头指针
L->next=NULL;
while(p!=NULL)
{
q=p;
p=p->next;
q->next=L->next;
L->next=q;
}
return OK;
}
1.3.5. 寻找最大元素对
LinkList Adjmax(LinkList h)//练习2:寻找最大元素对
{
LinkList p, p1, q;
int m0, m1;
p = h->next;
p1 = p;
if(p1 == NULL)
return p1; //表空返回//
q = p->next;
if(q == NULL)
return p1; //表长=1时的返回//
m0 = p->data + q->data; //相邻两结点data值之和//
while (q->next != NULL)
{
p = q;
q = q->next; //取下一对相邻结点的指针//
m1 = p->data + q->data;
if(m1 > m0)
{
p1 = p;
m0 = m1;
}
}//取和为最大的第一结点指针//
return p1;
}
1.4. 双链表
1.4.1. 双链表的创建
void CreateList(DuLinkList *L,int n)
{
DuLinkList p,r;
int i;
srand(time(NULL));
*L = (DuLinkList)malloc(sizeof(DulNode));
(*L)->data = -1;
(*L)->prior = NULL;
(*L)->next = NULL;
}
1.4.2. 双链表的插入
n->next = p1
n->pro = p2
p1->pro = n
p1->next = p2
int ListInsert(DuLinkList *L,int i,data_t e)
{
int j;
DuLinkList p,s;
p=*L;
j=1;
while(p && j<i)
{
p=p->next;
j++;
}
if(!p || j>i)
{
printf("第%d个位置不存在!\n",i);
return ERROR;
}
s=(DuLinkList)malloc(sizeof(DulNode));
s->data=e;
s->prior=p;
s->next=p->next;
p->next->prior=s;
p->next=s;
return OK;
}
1.4.2. 双链表的删除
int ListDelete(DuLinkList *L,int i,data_t *e)
{
int j;
DuLinkList p;
p=*L;
j=1;
while(p->next && j<=i)
{
p=p->next;
j++;
}
if(!(p->next) || j>i+1)
{
printf("第%d个位置不存在!\n",i);
return ERROR;
}
*e=p->data;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
p=NULL;
return OK;
}
1.4.2. 双链表的遍历
int GetElem(DuLinkList L,int i,data_t *data)//读取双向链表的第i个元素
{
int j;
DuLinkList p;
p = L;
j = 1;
while(p && j<i)
{
p = p->next;//让p指向下一个节点
j++;
}
if(!p || j>i)
{
printf("第%d个位置不存在!\n",i);
return ERROR;
}
*data = p->data;
return OK;
}
1.4.2. 双链表的销毁
int ClearList(DuLinkList *L)
{
DuLinkList p,q;
p=(*L)->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
(*L)->next=NULL;
return OK;
}