链表的核心要素
每个节点由数据域和指针域组成
指针域指向下一个节点的内存地址
结构体的定义
typedef struct _LinkNode {
ElemType data;
struct _LinkNode* next;
}LinkList, LinkNode;
单链表
初始化
bool initList(LinkList*& L) {
L = new LinkNode;
if (!L) return false;
L->next = NULL;
return true;
}
增加元素
前插法
bool insertFrontList(LinkList*& L,LinkNode* node) {
if (!L || !node) return false;
node->next = L->next;
L->next = node;
return true;
}
尾插法
bool insertRearList(LinkList*& L, LinkNode* node) {
if (!L || !node) return false;
//找到最后一个节点
LinkNode* last = NULL;
last = L;
while (last->next) last = last->next;
node->next = NULL;
last->next = node;
return true;
}
插入元素
bool insertList(LinkList*& L, int pos, ElemType& e) {
int j = 0;
LinkList* p, * s;
//在带头结点的单链表 L 中第 i 个位置插入值为 e 的新结
p = L;
while (p && j < pos - 1) {//查找第 i-1 个结点,p 指向该结点
p = p->next;
j++;
}
if (!p || j > pos - 1) return false;
s = new LinkNode;
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
遍历链表
void printList(LinkList*& L) {
LinkNode* p;
p = L->next;
while (p) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
获取元素
bool getElem(LinkList*& L, int pos, ElemType& e) {
LinkList* p;
int j = 1;
p = L->next;
while (p && j < pos) {
p = p->next;
j++;
}
if (!p || j > pos) return false;
e = p->data;
return true;
}
查找元素
bool findElem(LinkList*& L, ElemType e) {
LinkList* p;
p = L->next;
while (p && p->data != e) {
p = p->next;
}
if (!p) return false;
}
删除节点
bool deleteList(LinkList*& L, int pos) {
int j = 0;
LinkNode* p, * q;
p = L;
while (p->next && j < pos - 1) {
p = p->next;
j++;
}
if (!(p->next) || j > pos - 1) return false;
q = p->next;
p->next = q->next;
delete q;
return true;
}
销毁链表
void destroyList(LinkList*& L) {
LinkList* p = L;
cout << "销毁链表" << endl;
while (p) {
L = L->next;
cout << "销毁节点" << p->data << endl;
delete p;
p = L;
}
}
测试
int main() {
LinkList* L = NULL;
LinkNode* s = NULL;
//1. 初始化一个空的链表
initList(L);
//2. 使用前插法插入数据
int n;
cout<<"前插法创建单链表"<<endl;
cout<<"请输入元素个数 n:";
cin>>n;
cout<<"\n 请依次输入 n 个元素:" <<endl;
while(n>0){
s = new LinkNode; //生成新节点 s
cin>>s->data;
insertFrontList(L, s);
n--;
}
//4. 单链表的输出
printList(L);
//5. 任意位置插入元素
for (int j = 0; j < 3; j++) {
int i, x;
cout << "请输入插入的位置和元素(用空格隔开):";
cin >> i;
cin >> x;
if (insertList(L, i, x)) {
cout << "插入成功.\n\n";
}
else {
cout << "插入失败!\n\n";
}
printList(L);
}
//6. 单链表根据位置获取元素
int element = 0;
if (getElem(L, 2, element)) {
cout << "获取第二个元素成功, 值:" << element << endl;
}
else {
cout << "获取第二个元素失败!" << endl;
}
//7. 单链表根据值查询元素所在的位置
int index = 0;
if (findElem(L, 10, index)) {
cout << "查找元素 10 存在,所在位置: " << index << endl;
}
else {
cout << "不存在元素 10." << endl;
}
//8. 单链表删除元素
if (deleteList(L, 2)) {
cout << "删除第 2 个元素成功!" << endl;
printList(L);
}
else {
cout << "删除第 2 个元素失败!" << endl;
}
//9. 销毁单链表
destroyList(L);
return 0;
}
循环链表
空的循环链表
例:有 10 个小朋友按编号顺序 1,2,。。。,10 顺时针方向围成一圈。从 1 号开 始顺时针方向 1,2,。。。,9 报数,凡报数 9 者出列(显然,第一个出圈为 编号 9 者)。 最后一个出圈者的编号是多少?第 5 个出圈者的编号是多少?
#include <iostream>
using namespace std;
typedef struct _LinkNode {
int data;
struct _LinkNode* next;
}LinkNode, LinkList;
bool initList(LinkList*& L) {
L = new LinkNode;
if (!L) return false;
L->next = L;
L->data = -1;
return true;
}
bool insertRearList(LinkList*& L, LinkNode* node) {
LinkNode* last = NULL;
if (!L || !node) return false;
last = L;
while (last->next!=L) last = last->next;
node->next = L;
last->next = node;
return true;
}
void printList(LinkList* L) {
LinkList* p;
if (!L || L == L->next) {
cout << "链表为空" << endl;
return;
}
p = L->next;
while (p != L) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
bool Joseph(LinkList*&L,int interval) {
LinkList* p, * q;
int i = 0, j = 0, times = 0, num = 0;
p = L;
if (!L || p->next == L) {
cout << "链表为空!" << endl;
return false;
}
if (interval < 1) {
cout << "报数淘汰口令不能小于1" << endl;
return false;
}
do {
i += interval;
while (p->next) {//查找第 i 个结点,p 指向该结点的上一个节点
if (p->next != L) j++;
if (j >= i) break;
p = p->next;
}
times++;
q = p->next;
num = q->data;
if (times == 5) cout << "第五个出圈的编号是:" << num << endl;
printf("cur: %d last: %d next: %d\n", q->data, p->data, q->next->data);
p->next=q->next;
delete q;
printList(L);
} while (L->next != L);
cout << "最后一个出圈的编号是:" << num << endl;
return true;
}
int main() {
int i, x;
LinkList* L;
LinkNode* s;
//1. 初始化一个空的循环链表
if (initList(L)) {
cout << "初始化一个空的循环链表!\n";
}
//2. 创建循环链表(尾插法)
cout << "尾插法创建循环链表, 插入 10 个元素..." << endl;
i = 0;
while ((++i) <= 10)
{
s = new LinkNode;//生成新结点
s->data = i; //输入元素值赋给新结点的数据域
s->next = NULL;
if (insertRearList(L, s)) {
cout << "插入成功!" << endl;
}
else {
cout << "插入失败!" << endl;
}
}
cout << "尾插法创建循环链表输出结果:\n";
printList(L);
//3. 解答约瑟夫问题
Joseph(L, 9);
return 0;
}
双链表
双链表定义
typedef struct _DbLinkNode {
int data;
struct _DbLinkNode* prev;
struct _DbLinkNode* next;
}DbLinkNode, DbLinkList;
初始化双链表
bool initDbList(DbLinkList*& L) {
L = new DbLinkNode;
if (!L) return false;
L->data = -1;
L->next = NULL;
L->prev = NULL;
return true;
}
头插法创建双链表
bool insertFrontDbList(DbLinkList*& L, DbLinkNode* node) {
if (L->next == NULL) {
node->next = NULL;
node->prev = L;
L->next = node;
}
else {
L->next->prev = node;
node->next = L->next;
node->prev = L;
L->next = node;
}
return true;
}
尾插法创建双链表
bool insertRearDbList(DbLinkList*& L, DbLinkNode* node) {
if (!L || !node) return false;
DbLinkList* last = L;
while (last->next) last = last->next;
node->next = NULL;
node->prev = last;
last->next = node;
return true;
}
指定位置插入元素
bool insertDbList(DbLinkList*& L, int i, int& e) {
if (!L || !L->next) return false;
if (i < 1) return false;
int j = 0;
DbLinkList * p, * s;
p = L;
while (p && j < i) {//查找位置为 i 的结点,p 指向该结点
p = p->next;
j++;
}
if (!p || j != i) {
cout << "不存在节点:" << i << endl;
return false;
}
cout << "p: " << p << endl;
s = new DbLinkNode;//生成新节点
s->data = e;
s->next = p;
s->prev = p->prev;
p->prev->next = s;
p->prev = s;
return true;
}
遍历双链表
void printDbList(DbLinkList*& L) {
DbLinkNode* p = NULL;
if (!L) {
cout << "链表为空." << endl;
return;
}
p = L;
while (p->next) {
cout << p->next->data << "\t";
p = p->next;
}
//逆向打印
cout << endl << "逆向打印" << endl;
while (p) {
cout << p->data << "\t";
p = p->prev;
}
cout << endl;
}
获取元素
bool getElemDbList(DbLinkList*& L, int i, int& e) {
int index;
DbLinkList* p;
if (!L || !L->next) return false;
p = L->next;
index = 1;
while (p && index < i) {//顺链表向后扫描,直到 p 指向第 i 个元素或 p 为空
p = p->next; //p 指向下一个结点
index++; //计数器 index 相应加 1
}
if (!p || index > i) {
return false; //i 值不合法,i>n 或 i<=0
}
e = p->data;
return true;
}
删除双链表
bool deleteDbList(DbLinkList*& L, int i) {
DbLinkList* p;
int index = 0;
if (!L || !L->next) {
cout << "双向链表为空!" << endl;
return false;
}
if (i < 1) return false; //不能删除头节点
p = L;
while (p && index < i) {
p = p->next;
index++;
}
if (!p) { //当节点不存在时,返回失败
return false;
}
p->prev->next = p->next; //改变删除结点前驱结点的 next 指针域
p->next->prev = p->prev; //改变删除节点后继节点的 prev 指针域
delete p; //释放被删除结点的空间
return true;
}
销毁双链表
void destroyDbList(DbLinkList*& L) {
//定义临时节点 p 指向头节点
DbLinkList* p = L;
cout << "销毁链表!" << endl;
while (p) {
L = L->next;//L 指向下一个节点
cout << "删除元素: " << p->data << endl;
delete p; //删除当前节点
p = L; //p 移向下一个节点
}
}
测试
int main() {
DbLinkList* L = NULL;
DbLinkNode* s = NULL;
//1. 初始化一个空的双向链表
initDbList(L);
//2. 使用前插法插入数据
int n;
cout << "前插法创建双向链表" << endl;
std::cout << "请输入元素个数 n:";
cin >> n;
cout << "\n 请依次输入 n 个元素:" << endl;
while (n > 0) {
s = new DbLinkNode; //生成新节点 s
cin >> s->data;
insertFrontDbList(L, s);
n--;
}
//3. 使用尾插法插入数据
cout << "尾插法创建双向链表" << endl;
std::cout << "请输入元素个数 n:";
cin >> n;
cout << "\n 请依次输入 n 个元素:" << endl;
while (n > 0) {
s = new DbLinkNode; //生成新节点 s
cin >> s->data;
insertRearDbList(L, s);
n--;
}
//4. 双向链表的输出
printDbList(L);
//5. 任意位置插入元素
for (int j = 0; j < 3; j++) {
int i, x;
cout << "请输入插入的位置和元素(用空格隔开):";
cin >> i;
cin >> x;
if (insertDbList(L, i, x)) {
cout << "插入成功.\n\n";
}
else {
cout << "插入失败!\n\n";
}
printDbList(L);
}
//6. 双向链表根据位置获取元素
int element = 0;
if (getElemDbList(L, 2, element)) {
cout << "获取第二个元素成功, 值:" << element << endl;
}
else {
cout << "获取第二个元素失败!" << endl;
}
//7. 双向链表删除元素
if (deleteDbList(L, 2)) {
cout << "删除第 2 个元素成功!" << endl;
printDbList(L);
}
else {
cout << "删除第 2 个元素失败!" << endl;
}
if (deleteDbList(L, 1)) {
cout << "删除第 1 个元素成功!" << endl;
printDbList(L);
}
else {
cout << "删除第 1 个元素失败!" << endl;
}
//8. 销毁双向链表
destroyDbList(L);
return 0;
}