数据结构与算法------链表
一、单链表
(1)用代码定义单链表
// ********************************* < 定义单链表 > *********************************
typedef struct LNode // 定义单链表结点类型
{
int data; // 每个结点存放一个数据元素
struct LNode *next; // 指针指向下一个结点
}LNode, *LinkList;
// 要定义一个单链表时,只需声明一个头指针 “L”,指向单链表的第一个结点
LNode *L; // 声明一个指向单链表 "头节点" 的指针(强调这是一个结点!!!)
// 或者(两种形式等价)
LinkList L; // 声明一个指向单链表 "头节点" 的指针(强调这是一个单链表)
(2)创建单链表
// ********************************* < 创建单链表 > *********************************
// 创建“不带头节点”的单链表!!!!!!!!!!!!!!!!!!!(操作不方便)
LinkList L; // 声明一个指向单链表的指针
bool InitList(LinkList &L)
{
L = Null; // 空表,没有任何结点
return true;
}
// 初始化一个空表
InitList(L);
// 创建“带头节点”的单链表!!!!!!!!!!!!!!!!!!!(操作方便)
LinkList L; // 声明一个指向单链表的指针
bool InitList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode)); // 分配一个头节点
if (L == NULL) // 若内存不足,则创建失败(增加代码健壮性)
{
return false;
}
L->next = NULL; // 头节点之后暂时还没有节点(防止脏数据)
return true;
}
// 初始化一个空表
InitList(L);
(3)单链表的插入
// ********************************* < 单链表的插入 > *********************************
// 单链表“按位序插入”(带头节点)!!!!!!!!!!!!!!!!!!!
bool ListInsert(LinkList &L, int i, int e) // 注意链表前的(&)引用符号!!!
{
if (i < 1)
{
return false;
}
LNode *p; // 指针 p 指向当前扫描到的结点
int j = 0; // 当前 p 指向的是第几个结点
p = L; // L指向头节点,头节点是第 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; // 插入成功
}
// 单链表“按位序插入”(不带头节点)!!!!!!!!!!!!!!!!!!!
bool ListInsert(LinkList &L, int i, int e) // 注意链表前的(&)引用符号!!!
{
if (i < 1)
{
return false;
}
if (i == 1) // 插入第 1 个结点的操作与其他结点操作不同!!!!!!!!!!!!!!!!!!!!!!
{
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e; // 插入数据 e
s->next = L;
L = s; // 头指针指向新节点
return true;
}
LNode *p; // 指针 p 指向当前扫描到的结点
int j = 1; // 当前 p 指向的是第几个结点 !!!!!!!!!!!!!!!!!!!!!!!! 与带头结点的不同之处 !!!!!!!!!!!!!!!!!!!!!!
p = L; // L指向头节点,头节点是第 1 个结点(不存数据)
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;
}
// 指定结点的后插操作 !!!!!!!!!!!!!!!!!!!
bool InsertNextNode(LinkList *p, int e)
{
if (p == NULL) // 若内存分配失败
{
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s == NULL) // 若内存分配失败
{
return false;
}
s->data = e;
s->next = p->next;
p = s;
return true;
}
// 指定结点的前插操作 !!!!!!!!!!!!!!!!!!!
bool InsertPriorNode(LinkList *p, int e)
{
if (p == NULL) // 若内存分配失败
{
return false;
}
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s == NULL) // 若内存分配失败
{
return false;
}
// 即创建一个 结点s 来代替 结点p,结点p 作为前插结点!!!!!!
s->next = p->next;
p->next = s;
s->data = p->data; // p中元素复制给 s
p->data = e; // p中元素覆盖为 e
return true;
}
(4)单链表的删除
// ********************************* < 单链表的删除 > *********************************
// 单链表“按位序删除”(带头节点)!!!!!!!!!!!!!!!!!!!
bool ListDelete(LinkList &L, int i, int &e)
{
if (i < 1)
{
return false;
}
LNode *p; // 指针 p 指向当前扫描到的结点
int j = 0; // 当前 p 指向的是第几个结点
p = L; // L 指向头节点,头节点为第0个结点(不存数据)
while (p != NULL && j < i - 1) // 循环找到第 i-1 个结点
{
p = p->next;
j++;
}
if (p == NULL) // i值不合法
{
return false;
}
if (p->next == NULL) // 第 i-1 个结点后已无结点
{
return false;
}
LNode *q = p->next; // 令 q 指向需要被删除结点
e = q -> data; // 用 e 存放返回元素的值
p->next = q->next; // p 指向 q 之后结点,即断开 q 结点
free(q); // 释放 q 结点,删除成功
return true;
}
// 指定结点的删除操作 !!!!!!!!!!!!!!!!!!!
bool DeleteNode(LNode *p)
{
if (p == NULL)
{
return false;
}
LNode *q = p->next; // 令 q 指向 p 的后继节点
p->data = p->next->data; // 和后继节点交换数据域
p->next = q->next; // p 指向 q 的后继节点,即断开 q
free(q); // 释放结点 q,即删除成功
return true;
}
(5)单链表的查找及长度计算
// ********************************* < 单链表的查找 > *********************************
// 按值查找操作 !!!!!!!!!!!!!!!!!!!
LNode *FindElem(LinkList L, int e)
{
LNode *p = L->next; // p 指向第一个结点
while (p != NULL && p->data != e) // 从第一个结点开始查找数据为 e 的结点
{
p = p->next;
}
return p; // 找到后返回该结点指针,否则返回 NULL
}
// 求链表长度 !!!!!!!!!!!!!!!!!!!
int GetLength(LinkList L)
{
LNode *p = ; // p 指向头节点!!!!!!
int len = 0; // 统计表长
while (p != NULL) // 从第一个结点开始查找数据为 e 的结点
{
p = p->next;
++len;
}
return len; // 找到后返回该结点指针,否则返回 NULL
}
(6)“尾插法” 建立单链表
// ********************************* < 尾插法建立单链表 > *********************************
LinkList List_TailInsert(LinkList &L) // 正向建立链表
{
L = (LinkList)malloc(sizeof(LNode)); // 建立头节点
LNode *s; // s 指向待插入部分
LNode *r = L; // r 为表尾指针
int x; // 待插入元素
scanf("%d", &x);
while (x != 9999) // 假定输入 9999 表示插入结束
{
// 在 r 之后插入元素 x
s = (LinkList)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s; // r 始终指向表尾
scanf("%d", &x);
}
r->next = NULL; // 尾结点指针置空
return L; // 返回建立好的链表的头结点
}
(7)“头插法” 建立单链表(链表逆置)
// ********************************* < 头插法建立单链表(链表逆置) > *********************************
// 将需要逆置的链表顺序遍历,用头插法插入到另一个链表中,即实现了链表逆置!!!!!!!!!!!
LinkList List_HeadInsert(LinkList &L) // 正向建立链表
{
L = (LinkList)malloc(sizeof(LNode)); // 建立头节点
L->next = NULL; // 初始为空链表 !!!!!!!!很重要!!!!!!!!!
LNode *s; // s 指向待插入部分
int x; // 待插入元素
scanf("%d", &x);
while (x != 9999) // 假定输入 9999 表示插入结束
{
// 在 r 之后插入元素 x
s = (LinkList)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s; // 插入新结点,L 为头指针
scanf("%d", &x);
}
return L; // 返回建立好的链表的头结点
}