1、链表的特征
n个节点离散分配;
彼此通过指针相连;
每个节点只有一个前趋节点,且每个节点只有一个后续节点;
首节点没有前趋节点、尾节点没有后续节点;
专业术语:
首节点:第一个有效节点;
尾节点:最后一个有效节点;
头结点:第一个有效节点之前的节点,头结点不存放有效数据,加头结点的主要目的是为了方便对链表进行操作,头结点的数据类型和首节点的类型一致;
头指针:指向头结点的指针变量;
尾指针:指向尾节点的指针变量;
确定一个链表需要几个参数:
只需要一个参数:头指针,通过头指针可以推算出链表的其他所有信息
2、链表的分类
单链表:
合并单链表的算法:
void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc)
{
//已知单链表La和Lb中元素按照非递减排列
//归并La和Lb得到新的链表Lc,Lc的元素也按值非递减排列
pa = La->next;
pb = Lb->nexe;
Lc = pc = la;
while(pa&&pb)
{
if(pa->data<=pb->data)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
else
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa?pa:pb; //插入剩余段
free(Lb);
}
双链表:每一个节点有两个指针域;
循环链表:能通过任何一个节点找到其他结点;
非循环链表:
3、算法
遍历:
查找:
清空:
销毁:
求长度:
排序:
删除节点:
错误方法1:
{
p->pNext = p-pNext->pNext; //会导致内存泄漏(没有释放内存)
}
正确方法2:
{
r = p->pNext;
p->pNext = r->pNext;
delete r;
}
插入节点:
向p节点后插入q节点伪算法:
方法1:
{
r = p->pNext;
p->pNext = q;
q->pNext = r;
}
方法2:
{
q->pNext = p->pNext;
p->pNext = q;
}
4、链表创建和链表遍历(代码实现如下:C语言)
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct Node
{
int data;
struct Node * pNext;
}NODE,*PNODE;
PNODE creat_list();
void traverse_list();
int main(void)
{
PNODE pHead = NULL;
pHead = creat_list();//创建一个非循环单链表,将链表的头结点地址给pHead
traverse_list(pHead);
return 0;
}
PNODE creat_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("输入链表节点个数:");
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;
// pHead->pNext = pNew;
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;
}
printf("\n");
}