单链表的代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// 链表定义
typedef struct Lnode
{
int data; // 结点的数据域
struct Lnode* next; // 结点的指针域
}Lnode, *LinkList;
// 链表初始化
bool InitList(LinkList& L)
{
L = new Lnode; // 堆区开辟一个新结点作为链表的头结点(head),同时L作为头指针指向头结点
L->next = NULL; // 初始化,就是把头结点的指针域(next)指向空
return true;
}
// 判断是否为空
int IsEmpty(LinkList& L)
{
if (L->next == NULL) return TRUE;
return FALSE;
}
// 销毁单链表
int DestoryList(LinkList& L)
{
LinkList p; // 创建一个指针
while (L != NULL)
{
p = L;
L = L->next;
delete p;
}
return OK;
}
// 清空链表
int ClearList(LinkList& L)
{
LinkList p;
LinkList q; // 创建两个指针 用于依次释放结点
p = L->next; // 将指针 p 指向首元结点处
while (L != NULL)
{
q = p->next; // 将p指向的那个结点的指针域赋给 q,实际上就是让 q 指向 p 的下一个结点
delete p; // 删除 p指向的结点
p = q; // 让p跑到q指向的那个结点
}
L->next = NULL; // 头结点指针域为空
return OK;
}
// 求单链表的表长
int GetLength(LinkList L) //这里只要统计表长,不改变链表元素,因此不用 &
{
LinkList p; // 创建一个指针 或者写成:Lnode *p
p = L->next; // 将头结点的 next域值赋给 p,
int i = 0;
while (p != NULL) // 判断 指针p 指向的结点是否为空,不为空继续执行,为空跳出循环
{
i++;
p = p->next;
}
return i;
}
// 取链表中第 i 个元素的值
int GetElem(LinkList L, int i, int& e)
{
LinkList p;
p = L->next; // p指向首元结点
int j = 1; // 因为 p 已经在首元节点了,所以这里赋值直接使 j=1
while (p != NULL && j < i) // 依次向后扫描,直到p指向第i个元素或者p指向空
{
p = p->next;
j++;
}
if (!p || j>i)
{
cout << "out of range" << endl;
return ERROR;
}
e = p->data;
return OK;
}
// 查找 - 按值查找,返回地址 —— 地址要用 指针形式返回
Lnode* LocateElem(LinkList L, int e)
{
LinkList p;
p = L->next; // p指向首元结点
while (p != NULL && p->data != e)
{
p = p->next;
}
return p; // 不管找没找到都返回地址,只是没找到时 p 指向空处
}
// 查找 - 按值查找,返回位置序号
int LocateElem_L(LinkList L, int e)
{
LinkList p;
p = L->next; // p指向首元结点
int j = 1;
while (p != NULL && p->data != e)
{
p = p->next;
j++;
}
// 这里意思是 指针p 如果找到了肯定不指向空,因此返回j;如果没找到肯定遍历链表一遍了,所以指向空处,所以返回0
if (p != NULL) // p!=NULL 等价于 p
{
return j;
}
else
{
return 0;
}
}
// 在链表 第 i 个位置插入 新结点 e
bool InsertList(LinkList& L, int i, int e)
{
LinkList p; //
p = L; // 将指针p指向L,也就是指向头指针
int j = 0; // 所以这里从 j=0 开始算起
while (p != NULL && j<i-1) //寻找第 i-1 个结点,让指针 p 指向第 i-1 个结点位置
{
p = p->next;
++j;
}
if (!p || j>i-1) // i 大于表长 +1 或者小于1,插入位置违法
{
return ERROR;
}
Lnode *s = new Lnode; //创建一个新结点 LinkList s = Lnode *s
s->data = e;
s->next = p->next; // 这两步顺序不能颠倒,否则p的next域存放的地址找不到了
p->next = s;
return true;
}
// 删除结点
int DeleteLnode(LinkList& L, int i, int& e)
{
LinkList p; // 创建指针 p 指向第 i-1 个结点的位置,不能直接指向第 i 个位置,因为后面要删除
p = L;
int j = 0;
while (p->next != NULL && j<i-1)
{
p = p->next; // 寻找第 i-1 个结点,并令 p 指向这个位置的结点
++j;
}
if (!p || j>i-1)
{
return ERROR;
}
LinkList q; // 创建指针指向被删除的结点,临时保存结点地址,防止后面找不到
q = p->next; //把第 i 个结点的地址赋给指针 q保存
p->next = p->next->next; // 将第 i+1 个结点地址赋给 第 i-1 个结点的next域
e = q->data; // 用e 保存第i个结点的数据域
// 释放删除结点的空间,另外说明:这里不特地删除指针 q,是因为指针 q 不是在堆区开辟,即不是 new 出来的,所以局部变量执行完毕后,还给栈区了
delete q;
return OK;
}
// 打印单链表所有数据域的数据
void PrintList(LinkList L)
{
LinkList p;
p = L->next; // p 指向首元结点
while (p != NULL)
{
cout << p->data << "\t";
p = p->next;
}
cout << endl;
}
// 单链表的建立 —— 头插法
void CreateListHead(LinkList& L, int n)
{
L = new Lnode; // 创建头结点;在堆区开辟;注意这里new过之后才是结点,否则就是一个指针
L->next = nullptr; // c++11 写法
for (int i = n; i >0; --i)
{
Lnode* p = new Lnode; // 创建新结点
cin >> p->data;
//解释:第一次把p的next域指针置为NULL,意思是最后一个结点的next域为空;而后来的结点的next域存放为前一个结点的地址
p->next = L->next; // 每次换尾巴
L->next = p; // 每循环一次就将 L的next域存放的地址 覆盖成 最新创建的结点的地址; 每次换头
}
}
// 单链表的建立 —— 尾插法
void CreateListTail(LinkList& L, int n) // 通过 & 带回链表
{
L = new Lnode; //创建头结点;在堆区开辟;注意这里new过之后才是结点,否则就是一个指针
L->next = nullptr;
LinkList r; // 创建一个指针,作为尾指针
r = L; // 尾指针指向头结点
for (int i = 0; i < n; i++) // 依次正序插入n次
{
Lnode* p = new Lnode; // 创建新结点
cin >> p->data;
p->next = nullptr;
r->next = p; // 插入到表尾
r = p; // 每连接上一个新结点,就把尾指针向后移到新结点上,所以称之为尾指针
}
}
// 单链表的合并 —— 比较数据域的数据大小升序排序
void MergeList(LinkList& La, LinkList& Lb, LinkList& Lc)
{
LinkList pa, pb, pc; // 指针
pa = La->next; // pa指向首元结点
pb = Lb->next;
pc = Lc = La; //用La的头结点作为Lc的头结点
while (pa && pb) // 等价于 pa->next != nullptr && pb->next != nullptr
{
if (pa->data <= pb->data) { pc->next = pa; pc = pa; pa = pa->next; }
else
{
pc->next = pb; pc = pb; pb = pb->next;
}
}
// 插入剩余段,看pa和pb那个剩余,把剩下的都赋给 pc
pc->next = pa ? pa : pb; // 三目运算 等价于:
delete Lb; // 释放Lb的头结点
}
int main()
{
// 实验1:尾插法
LinkList L1;
InitList(L1); // 链表初始化
cout << IsEmpty(L1) << endl; // 判断是否为空
CreateListTail(L1, 3); // 通过尾插法
InsertList(L1, 1, 10);
InsertList(L1, 3, 30);
InsertList(L1, 5, 50);
cout << IsEmpty(L1) << endl;
cout << GetLength(L1) << endl;
PrintList(L1);
DestoryList(L1);
// 实验2:头插法
LinkList L2;
InitList(L2); // 链表初始化
cout << IsEmpty(L2) << endl; // 判断是否为空
cout << "请依次输入数据:" << endl;
CreateListHead(L2, 3); // 通过头插法
InsertList(L2, 2, 10);
InsertList(L2, 4, 30);
InsertList(L2, 6, 50);
//cout << IsEmpty(L2) << endl;
cout << GetLength(L2) << endl;
PrintList(L2);
DestoryList(L2);
// 实验3:单链表的合并
LinkList La, Lb, Lc;
InitList(La);
InitList(Lb);
InsertList(La, 1, 10);
InsertList(La, 2, 30);
InsertList(La, 3, 50);
InsertList(La, 4, 70);
InsertList(Lb, 1, 5);
InsertList(Lb, 2, 21);
InsertList(Lb, 3, 33);
MergeList(La, Lb, Lc);
PrintList(Lc);
return 0;
}
双向链表:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// 双向链表定义
typedef struct DuLnode
{
int data; // 结点的数据域
struct DuLnode *prior, *next; // 结点的指针域 -
}DuLnode, *DuLinkList;
// 双向链表初始化
bool InitList(DuLinkList& L)
{
L = new DuLnode; // 堆区开辟一个新结点作为链表的头结点(head),同时L作为头指针指向头结点
L->prior = nullptr; //(prior)指向空
L->next = nullptr; // 初始化,就是把头结点的指针域(next)指向空
return true;
}
// 在双向链表的第 i 个位置插入元素
int ListInsert_DuL(DuLinkList& L, int i, int e)
{
DuLnode* p = new DuLnode;
p = L->next;
int j = 1;
while (p && j < i)
{
++j;
p = p->next;
}
if (j < i || j < 1) //如果i在链表范围内,上面的while循环的终止条件就是j<i
{
cerr << "out of range" << endl;
return false;
}
// 堆区开辟想要插入的结点
DuLnode* s = new DuLnode;
s->data = e;
// 重新链接
s->prior = p->prior; //第一步:p的prior域存放的是原来的前结点地址,赋给s的prior域,所以s的prior就能访问前节点
p->prior->next = s; //
s->next = p;
p->prior = s;
return OK;
}
// 双向链表删除某个元素
int DeleteListElem_Dul(DuLinkList& L, int i, int& e)
{
DuLnode* p = new DuLnode;
p = L->next;
int j = 1;
while (p && j < i)
{
++j;
p = p->next;
}
if (j < i || j < 1) //如果i在链表范围内,上面的while循环的终止条件就是j<i
{
cerr << "out of range" << endl;
return false;
}
e = p->data;
// 这里不考虑最后一个节点情况,如果考虑只要在后面两条加上 if 判断条件
p->prior->next = p->next; // 把p的后一个节点的地址赋给p的前一个节点next域保存
p->next->prior = p->prior; // 把p的前一个节点的地址赋给p的后一个节点prior域保存
delete p;
return OK;
}
int main()
{
// 这里就不再写了,思路都是跟单链表一样
// 如果有人看到,可以继续写 前插,后插,打印输出就能使用了
return 0;
}
视频的三道案例有机会再写~~