2.3.1 单链表的定义
typedef struct //定义 单链表结点 类型:结构体
{
int data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList; //LNode:强调结点 LinkList:强调链表
链表又分为 有头结点,无头结点 头指针始终指向链表第一个结点
无头结点:(无头结点 写代码麻烦 不推荐使用)
初始化:
bool InitList(LinkList &L)
{
L = NULL; //空表 无任何节点
return true;
}
判断空表:
bool Empty(LinkList L)
{
return (L == NULL);
}
有头结点:(带头结点 写代码方便 用过的都说好 [doge])
初始化:
bool InitList(LinkList &L)
{
L = (LNode*)malloc(sizeof(LNode));
if (L == NULL) //内存不足 申请空间失败
return false;
L->next = NULL; //L指向的头节点的指针置为空 头结点的数据域(data)不存储信息
return true; //头结点后无其它结点
}
判断空表:
bool Empty(LinkList L)
{
return (L->next==NULL);
}
求表长:
int Length(LinkList &L)
{
int l = 0;
LNode* p = L;
while (p->next != NULL)
{
p = p->next;
l++;
}
return l;
}
2.3.2 单链表基本操作的实现
1) 按序号 插入结点(在第i个位置 插入结点)注:可插表尾
//有头结点
bool ListInsert(LinkList &L, int i, int e) //i:第i个位置 e:结点值
{
if (i <= 0)return false;
LNode* p = L; //L指向头结点头结点是第0个结点
int j = 0; //当前p指向的是第几个结点
while (p != NULL&&j < i - 1) //循环找到要插入位置的前一个结点
{
p = p->next;
j++;
}
if (p == NULL)return false; //超出范围(不合法)
LNode* NewNode = (LNode*)malloc(sizeof(LNode));
NewNode->data = e;
NewNode->next = p->next; //插入顺序不能颠倒 否则导致信息缺失!!!
p->next = NewNode;
return true;
}
//无头结点
bool ListInsert(LinkList &L, int i, int e)
{
if (i <= 0)return false; //插入到第一个结点时 与其他不同 单独讨论
if (i == 1)
{
LNode* NewNode = (LNode*)malloc(sizeof(LNode));
NewNode->data = e;
NewNode->next = L;
L = NewNode;
return true;
}
int j = 1; //注意!!! 此时 j(当前p 指向的结点)是从第一个结点开始
LNode* p = L; //p表示 指向的结点
while (p != NULL&&j < i - 1) //循环 找目标结点
{
p = p->next;
j++;
}
if (p == NULL)return false;
LNode* NewNode = (LNode*)malloc(sizeof(LNode));
NewNode->data = e;
NewNode->next = p->next;
p->next = NewNode;
return true;
}
2.1) LNode* p(结点)后插入结点
//在结点之后插入元素e
bool InsertNextNode(LNode* p, int e)
{
if (p == NULL)return false;
LNode* NewNode = (LNode*)malloc(sizeof(LNode));
if (NewNode == NULL)return false;
NewNode->data = e;
NewNode->next = p->next;
p->next = NewNode;
return true;
}
2.2) LNode* p(结点)前插入结点
///
//时间复杂度O(n)
//在结点之前插入元素e(需要头指针LinkList &L)
bool InsertPriorNode(LinkList &L, LNode* p, int e)
{
if (p == NULL)return false;
LNode *t = L;
while (t != NULL&&t->next!=p) //(需要根据链表表头)找到目标结点的上一个结点 进行后插操作
{
t = t->next;
}
return InsertNextNode(t, e); //后插操作
}
//
//时间复杂度O(1)
//在结点之前插入元素e(不需要头指针LinkList &L)
bool InsertPriorNode(LNode* p, int e)
{
先后插
if (p == NULL)return false;
LNode *NewNode = (LNode*)malloc(sizeof(LNode));
if (NewNode == NULL)return false;
NewNode->data = e;
NewNode->next = p->next;
p->next = NewNode;
再交换两结点数据
NewNode->data = p->data;
p->data=e;
return true;
}
3.1) 删除某位置结点
//只考虑有头结点的情况
bool ListDelete(LinkList &L,int i, int &e)
{
int j = 0;
LNode* p = L;
while (p != NULL&&j < i - 1) //找到目标结点q的 前一个结点p
{
p = p->next;
j++;
}
if (p == NULL)return false;
if (p->next == NULL)return false;
LNode* q = p->next; //目标结点
e = q->data; //利用e返回
p->next = q->next;
free(q);
}
3.2) 删除某指定结点
//只考虑有头结点的情况
//需利用头指针
//时间复杂度O(n)
bool ListDelete(LinkList &L,LNode* p,int &e)
{
if (p == NULL)return false;
LNode* fp = L;
while (fp != NULL&&fp!=p->next) //找到目标结点的 前一个结点
{
fp = fp->next;
}
if (fp == NULL)return false;
e = p->data;
fp->next = p->next;
free(p);
return true;
}
//可删除任何结点!!!!!!!
//只考虑有头结点的情况
//不需利用头指针
//时间复杂度O(1)
bool ListDelete(LNode* p)
{
if (p == NULL)return false;
LNode* q = p->next; //找到p的下一个结点q偷天换日
p->data = q->data;
p->next = q->next;
free(q);
return true;
}
//不可删除最后一个结点!!!!!!!
4.1) 按位查找(返回结点)
//只考虑有头结点的情况
LNode* GetElem(LinkList &L, int i)
{
if (i < 0)return NULL;
int j = 0; //当前 p 指向的 是第几个结点
LNode* p = L;
while (p != NULL&&j < i) //找到第 i 个结点
{
p = p->next;
j++;
}
return p;
}
//将查找结点这一操作进行封装 直接使用GetNode(L,i-1)就可找到目标位置前一个结点
4.2) 按值查找(返回结点)
LNode* LocateElem(LinkList &L, int e)
{
LNode* p = L->next; //需从第一个结点开始查找
while (p != NULL&&p->data != e)
{
p = p->next;
}
return p;
}
5) 尾插法建立单链表
LinkList Link_TailInsert(LinkList &L)
{
LNode* t = L;
int x = 0;
while (scanf("%d", &x) != EOF)
{
LNode* p = (LNode*)malloc(sizeof(LNode));
p->data = x;
t->next = p;
t = p;
}
t->next = NULL; //表尾置为空
return L;
}
2.3.3 双链表
定义
typedef struct DNode
{
int data;
DNode* prior;
DNode* next;
}DNode,*DLinkList; //DNode:结点 DLinkList:(双)链表
判空
bool Empty(DLinkList& L)
{
if (L->next == NULL)
return false;
else return true;
}
1)双链表初始化
bool InitDLinkList(DLinkList& L)
{
L = (DNode*)malloc(sizeof(DNode));
if (L == NULL)return false;
L->prior = NULL; //头结点的prior 永远为 NULL
L->next = NULL;
return true;
}
2)双链表插入
//结点p之后插入
bool InsertNextDNode(DNode* p, DNode* New)
{
if (p == NULL || New == NULL)return false;
New->next = p->next;
if (p->next != NULL) //p之后有结点
{
p->next->prior = New;
}
p->next = New;
New->prior = p;
return true;
}
//结点p之前插入
bool InsertPriorDNode(DNode* p, DNode* New)
{
if (p == NULL || New == NULL)return false;
return InsertNextDNode(p->prior, New); //找到p的前一个结点 后插
}
3)双链表删除
//结点p之后删除
bool DeleteNextDNode(DNode*p)
{
if (p == NULL||p->next==NULL) //结点为空 或无后继
return false;
DNode*q = p->next;
p->next = q->next;
if (q->next != NULL)
q->next->prior = p;
free(q);
return true;
}
//销毁链表
void Destroy(DLinkList&L)
{
while (L->next != NULL) //依次删除 头节点之后的结点
DeleteNextDNode(L);
free(L);
L = NULL;
}
4)双链表遍历
//从前->后遍历
while (p != NULL)
{
//一系列操作
p = p->next;
}
//从后->前遍历(操作头结点)
while (p != NULL)
{
//一系列操作
p = p->prior;
}
//从后->前遍历(不包括头结点)
while (p->prior != NULL)
{
//一系列操作
p = p->prior;
}
2.3.4 循环链表
1 循环链表
2 静态链表
略