从零开始的数据结构(C语言)——链表
相关说明
链表是线性表的链式存储结构,其特点是一组数据元素的存储单元可以不连续。每个元素是一个对象,每个对象包括了两个域,即数据域和指针域,其中对于单链表而言,其指针域存储表示当前的点的后继存储位置的指针。(本章采用带头结点的单链表进行演示)
- 假设x为链表中的一个元素,则x->next则指向后继元素。
- 在链表中,除头节点外的每个节点都有且只有一个前驱元素,除尾节点外的每个节点都有且只有一个后继元素。
- 头指针表示链表的第一个节点、NULL表示链表的最后一个节点
单链表
单链表的定义
typedef int ElemType;
typedef struct LNode{
ElemType data;//数据域
struct LNode *next;//指针域
}LNode, *LinkList;//一般LNode* 用于定义任意节点的指针变量,LinkList用于定义头指针变量
单链表的基本操作
初始化单链表
int initList(LinkList &L)
{
L = (LinkList)malloc(sizeof(LNode));//为头指针开辟空间
L->next = NULL;//指针域置空
return 1;
}
查找
序号查找
查找第i(i>=1)个节点
int getElemList(LinkList L, int i, ElemType &e)
{
LNode* p = L->next;//防止头指针丢失,获取第一个有效节点
int j = 1;
while(p && j<i)//扫描
{
j++;
p = p->next;
}
if(!p || j>i)//若p为空则说明不存在这样的节点;若j>i则说明i<1,不符合规范
{
return -1;
}
e = p->data;
return 1;
}
按值查找
LNode* locateElemList(LinkList L, ElemType e)
{
LNode*p = L->next;
while(p&&p->data != e)
{
p = p->next;
}
return p;//当p为NULL时说明查找失败,反之查找成功
}
插入
将值为e的新节点插入到第i个节点位置
int insertElemList(LinkList &L, ElemType e, int i)
{
LNode*p = L;
int j = 0;
while(p&&j<i-1)
{
p = p->next;
i++;
}
if(!p||j>i-1)
{
return -1;
}
LNode *s = (LinkList)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return 1;
}
删除
将单链表的第i个节点删除
需要先找到第i-1个节点,将i-1节点的指针域指向第i+1个节点
int deleteElemList(LinkList &L, ElemType e, int i)
{
LNode*p = L;
int j = 0;
while(p->next&&j<i-1)
{
p = p->next;
j++;
}
if(!p->next || j>i-1)
return -1;
LNode* temp = p->next;
p->next = temp->next->next;
delete temp;
return 1;
}
单链表的创建
头插法
头插法数据读写顺序相反
void CreateList_F(LinkList &L, int n)
{
L = (LinkLIst)malloc(sizeof(LNode));
L->next = NULL;
for(int i=0;i<n;i++)
{
LNode* s = (LNode*)malloc(sizeof(LNode));
cin >> p->data;
p->next = L->next;
L->next = p;
}
}
尾插法
尾插法数据读写顺序相同
void CreateList_L(LinkList &L, int n)
{
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
LNode*r = L;
for(int i=0;i<n;i++)
{
LNode*s = (LNode*)malloc(sizeof(LNode));
cin >> p->data;
p->next = NULL;
r->next = p;
r = p;
}
}
单链表的转置
void swapElemList(LinkList &L)
{
LNode* p = L->next;
LNode *temp, *s = NULL;//temp用于暂存节点位置,s用于表示转置后链表的一个节点
while(p)
{
temp = p->next;//记录下一个节点的位置
p->next = s;
s = p;
p = temp;
}
L->next = s;
}
单链表合并
有序的两个单链表合并成一个单链表
void mergeElemList(LinkList &L1, LinkList &L2, LinkList &L3)
{
LNode* p1 = L1->next;
LNode* p2 = L2->next;
L3 = L1;
LinkList p3 = L3;
//比较,选取较小的节点插入L3
while(p1&&p2)//当两个单链表中的某个单链表的所有节点都已经合并入了L3中,退出
{
if(p1->data<=p2->data)
{
p3->next = p1;
p3 = p1;
p1 = p1->next;
}
else
{
p3->next = p2;
p3 = p2;
p2 = p2->next;
}
}
pc->next = p1? p1:p2;//当p1非空则插入p1,否则插入p2
}