定义:n 个节点离散分配;彼此通过指针相连;每个节点只有一个后续节点,首节点没有前驱节点,尾节点没有后续节点。
如下图:
专业术语:
首节点:第一个有效节点
尾节点:最后一个有效节点
头节点:头节点的数据类型和首节点的数据类型相同。 第一个有效节点之前的那个节点;头节点并不存放存放有效数据;加头节点的目主要是为了方便对链表的操作。
头指针:指向头节点的指针变量
尾指针:指向尾节点的指针变量
头节点 -首节点。。尾节点【头节点并没有存储有效数据,也没有存放链表中有效节点的个数。 首节点开始存放有效数据。
在链表前边加一个没有实际意义的头节点, 可以方便对链表的操作。头节点于之后节点的数据类型相同】
分类:
算法:
链表的优缺点:
如果希望通过一个函数来对链表进行处理,我们至少需要接受链表的哪些参数?
答:只需要一个参数:头指针。因为我们通过头指针可以推算出链表的其他所有参数
每一个链表节点的数据类型该如何表示的问题
示例:
#include<stdio.h>
typedef struct Node
{
int data;// 数据域
struct Node * pNext;// 指针域
}NODE,*PNODE;//NODE 等价于 struct Node ,PNODE等价于 struct Node *
int main(void)
{
return 0;
}
分类:
单链表:每个链表的指针域只能指向后面的节点
双链表:每一个节点有两个指针域
循环链表:能通过任何一个节点找到其他所有的结点
非循环链表:
非循环单链表插入节点伪算法讲解
遍历查找
清空
销毁
求长度
排序
删除节点
插入节点
插入算法 1、r=p->pNext;p->Next=q;q->pNext=r;
插入算法 2、q->Next=p->pNext;p->Next=q; 【p,q 不是节点,是指针变量】
链表创建和遍历算法示例:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
int data;// 数据域
struct Node * pNext;// 指针域
}NODE,*PNODE;//NODE 等价于 struct Node ,PNODE等价于 struct Node *
// 函数声明
PNODE create_list(void);
void traverse_list(PNODE pHead);
int main(void)
{
PNODE pHead=NULL;//等价于 struct Node *pHead=NULL ;
pHead=create_list();//creat_list() 功能:创建一个非循环单链表 ,并将该链表的头节点的地址赋值给 pHead
traverse_list(pHead);
return 0;
}
PNODE create_list(void)
{
int len;// 用来存放有效节点的个数
int i;
int val;// 用来临时存放用户输入的节点的值
// 分配了一个不存放有效数据的头节点
PNODE pHead=(PNODE)malloc(sizeof(NODE));
if(NULL==pHead)
{
printf(" 分配失败,程序终止! \n");
exit(-1);
}
PNODE pTail=pHead;
pTail->pNext=NULL;
printf(" 请输入您需要生成的链表节点的个数: len=");
scanf("%d",&len);
for (i=0;i<len;i++)
{
printf(" 请输入第 %d 个节点的值 :",i+1);
scanf("%d",&val);
PNODE pNew=(PNODE)malloc(sizeof(NODE));
if(NULL==pNew)
{
printf(" 分配失败,程序终止! \n");
exit(-1);
}
pNew->data=val;// 挂
pTail->pNext=pNew;
pNew->pNext=NULL;
pTail=pNew;
}
return pHead;
}
void traverse_list(PNODE pHead)
{
PNODE p=pHead->pNext;
while(NULL!=p)
{
printf("%d ",p->data);
p=p->pNext;// 不连续,不能用 p++
}
printf("\n");
return;
}