一、链表的定义
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
一般来说,数组的存储方式是这样的:
而链表的存储方式是这样的:
可见链表的是通过指针next进行联系,就像火车一样头连尾的形式。
链表包含数据域和指针域。
二、链表的建立
1.初始化一个单链表的结点
typedef int ElemType;
typedef struct LNode//定义单链表的节点类型
{
ElemType data;//每个节点存放一个数据类型
struct LNode *next;//指针指向下一个节点
}LNode,*LinkList;//struct LNode重命名为LNode,用LinkList来表示这是一个指向struct LNode 的指针
注:可以将int改为你想用的元素类型,为了统一写法而换成ElemType。
LNode*和LinkList本质上是一样的,LNode*强调这是一个结点,LinkList强调这是一个单链表。
2.初始化一个空链表(带头结点)
为了方便写代码,一般链表都带头结点,本文写的也都是带头结点的。
//初始化一个空链表
bool InitList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode));//分配一个头节点
if (L == NULL)//内存不足,分配失败
return false;
L->next = NULL;//头节点之后暂时没有节点
return true;
}
3.头插法建立单链表
//头插法建立单链表
LinkList List_HeadInsert(LinkList& L)//逆向建立单链表
{
LNode* s;
int x;
L = (LNode*)malloc(sizeof(LNode));//创建头结点
L->next = NULL;//初始为空链表
scanf("%d", &x);//输入结点的值
while (x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;//将新结点插入表中,L为头指针
scanf("%d", &x);
}
}
4.尾插法建立单链表
//尾插法建立单链表
LinkList List_Taillnsert(LinkList& L)//正向建立单链表
{
int x;//设ElemType为整形
L = (LinkList)malloc(sizeof(LNode));//设置头结点
LNode* s, * r = L;//r为表尾指针
scanf("%d", &x);//输入结点的值
while (x != 9999)
{
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;//r指向新的表尾结点
scanf("%d", &x);
}
r->next = NULL;//尾结点指针置空
return L;
}
5.按位序插入(在第i个位置插入元素e)
bool ListInsert(LinkList& L, int i, ElemType e)
{
if (i < 1)
return false;
LNode*p;
int j = 0;//当前p指向的哪个结点
p = L;//p指向头结点,头结点是第0个结点(不存数据)
while (p != NULL && j < i - 1)//循环找到i-1个结点
{
p = p->next;
j++;
}
if (p == NULL)//i值不合法
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;//将结点s连到p之后
return true;//插入成功
return InsertNextNode(p, e);
}
6.指定节点后插
bool InsertNextNode(LNode* p, ElemType e)
{
if (p == NULL)//i值不合法
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)//内存分配失败
return false;
s->data = e;
s->next = p->next;
p->next = s;//将结点s连到p之后
return true;//插入成功
}
7.指定节点前插
//前插操作:在p结点之前插入结点s
bool InsertPriorNode(LNode *s,LNode *p)
{
if (p==NULL||s==NULL)
return false;
s->next = p->next;
p->next = s;//s连到p之后
ElemType temp = p->data;//交换数据域部分
p->data = s->data;
s->data = temp;
}
8.删除指定节点
//删除指定结点p
bool DeleteNode(LNode* p)
{
if (p == NULL)
return false;
LNode* q = p->next;//令q指向*p后续结点
p->data = q->data;//和后续结点交换数据域
p->next = q->next;//将*q结点从链中断开
free(q);//释放后续结点的存储空间
return true;
}
9.按位查找,返回第i个元素
//按位查找,返回第i个元素(带头结点)
LNode* GetElem(LinkList& L, int i)
{
if (i < 0)
return NULL;
LNode* p;//指针p指向当前扫描到的结点
int j = 0;//指针p当前指向哪个结点
p = L;//L指向头结点,头结点是第0个结点(不存数据)
while (p != NULL && j < i)//循环找到第i个结点
{
p = p->next;
j++;
}
return p;
}
10.按值查找,找到数据域为e的结点
//按值查找,找到数据域==e的结点
LNode* LocateElem(LinkList& L, int e)
{
LNode* p = L->next;//从第一个结点开始查找数据域为e的结点
while (p != NULL && p->data != e)
{
p = p->next;
}
return p;//找到后返回该结点指针,否则返回NULL
}
暂时总结那么多,后面有时间想起来再补