【数据结构】链表
1.什么是链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
2.链表的种类
实际应用中链表的结构非常多样,大致为以下几种:
- 单向或双向
- 带头节点或不带头节点
- 循环或不循环
本文将介绍几种常见链表
3.单链表
首先我们要知道,链表是由节点构成的,以下是一个单链表节点的构成
data为该节点所存的数据,next用于存放下一个节点的地址
因此一个节点可表示为:
struct Node {
int data;
Node* next;
};
数据域:data 指针域:next
而链表的创建,就是将一个一个节点连接起来的过程,以单链表的尾插法为例:
1.创建头节点(head)
2.创建下一个节点,其位置在上一个节点后,同时上一个节点的指针域(next)指向该节点
3.重复以上过程,直到创建该链表的最后一个节点
链表的初始化
Node* initial_link()
{
Node* head = new Node;//分配内存
if (head == NULL)
{
cout << "分配失败,程序退出";
exit(-1);
}
head->next = NULL;
return head;
}
链表求长
int link_length(Node* head)
{
Node* rear = head->next;
int n = 0;
while (rear != NULL)
{
n++;
rear = rear->next;
}
return n;
}
链表尾插法
void backlink(Node* head,int n)//n为要传入链表数据的个数
{
Node* rear = head;//定义一个rear(用于指向插入节点的前一个节点),方便后续插入操作
int i;
for (i = 0; i < n; i++)
{
Node* newnode = new Node;//为newnode申请空间
newnode->next = NULL;
cin >> newnode->data;//传入数据
rear->next = newnode;
rear = newnode;
}
}
链表头插法
void headlink(Node* head,int n)//n为要传入链表数据的个数
{
int i;
for (i = 0; i < n; i++)
{
Node* newnode = new Node;//为newnode申请空间
newnode->next = head->next;
cin >> newnode->data;//传入数据
head->next = newnode;
}
}
//相比于尾插法,头插法由于直接插在head后面,因此省去定义rear的步骤
链表的遍历输出
void printlink(Node* head)
{
Node* rear = head->next;
while (rear != NULL)
{
cout << rear->data;
rear = rear->next;
}
}
链表是否为空的判断
void IsEmpty(Node* head)
{
if (head->next == NULL)//判断第一个节点是否为NULL
{
cout << "true";
}
else
cout << "false";
}
链表的查找
Node* findlink(Node *head,int g)//查找第g个节点
{
if (g > link_length(head))//判断g是否超出链表长度
{
cout << "不存在";
return NULL;
}
Node* rear = head;
int i = 0;
while (i != g)
{
rear = rear->next;
i++;
}
return rear;//如果存在则返回该节点
}
链表的节点插入
void insertlink(Node* head,int g,int newdata)//在第g个节点后插入数据为newdata的新节点
{
if (g > link_length(head))//判断g是否超出链表长度
{
cout << "ERROR";
return;
}
Node* pre_newnode=findlink(head, g);//调用链表的查找
Node *newnode = new Node;
newnode->next =pre_newnode->next;
newnode->data = newdata;
pre_newnode->next = newnode;
}
链表的节点删除
void deletelink(Node* head, int g)//删除第g个节点
{
if (g > link_length(head))//判断g是否超出链表长度
{
cout << "ERROR";
return;
}
Node* pre_deletenode = findlink(head, g-1);//查找第g个节点的前一个节点
Node* deletenode = pre_deletenode->next;
pre_deletenode->next = deletenode->next;
delete(deletenode);//释放内存
}
链表的销毁
void destorylink(Node *head)
{
Node* rear1 = head->next;
Node* rear2 = NULL;//定义两个rear,rear1负责向后遍历,rear2负责释放内存
while (rear1 != NULL)
{
rear2 = rear1;
rear1 = rear1->next;
delete(rear2);
}
head->next = NULL;
}
最后完整代码
#include<bits/stdc++.h>//偷个懒,直接引万能头文件
using namespace std;
struct Node {
int data;
Node* next;
};
Node* initial_link()
{
Node* head = new Node;
if (head == NULL)
{
cout << "分配失败,程序退出";
exit(-1);
}
head->next = NULL;
return head;
}
int link_length(Node* head)
{
Node* rear = head->next;
int n = 0;
while (rear != NULL)
{
n++;
rear = rear->next;
}
return n;
}
void backlink(Node* head, int n)
{
Node* rear = head;
int i;
for (i = 0; i < n; i++)
{
Node* newnode = new Node;
newnode->next = NULL;
cin >> newnode->data;
rear->next = newnode;
rear = newnode;
}
}
void printlink(Node* head)
{
Node* rear = head->next;
while (rear != NULL)
{
cout << rear->data;
rear = rear->next;
}
}
void IsEmpty(Node* head)
{
if (head->next == NULL)
{
cout << "true";
}
else
cout << "false";
}
Node* findlink(Node* head, int g)
{
if (g > link_length(head))
{
cout << "不存在";
return NULL;
}
Node* rear = head;
int i = 0;
while (i != g)
{
rear = rear->next;
i++;
}
return rear;
}
void insertlink(Node* head, int g, int newdata)
{
if (g > link_length(head))
{
cout << "ERROR";
return;
}
Node* pre_newnode = findlink(head, g);
Node* newnode = new Node;
newnode->next = pre_newnode->next;
newnode->data = newdata;
pre_newnode->next = newnode;
}
void deletelink(Node* head, int g)
{
if (g > link_length(head))
{
cout << "ERROR";
return;
}
Node* pre_deletenode = findlink(head, g - 1);
if (pre_deletenode == NULL)
{
cout << "ERROR";
return;
}
Node* deletenode = pre_deletenode->next;
pre_deletenode->next = deletenode->next;
delete(deletenode);
deletenode = NULL;
}
void destorylink(Node* head)
{
Node* rear1 = head->next;
Node* rear2 = NULL;
while (rear1 != NULL)
{
rear2 = rear1;
rear1 = rear1->next;
delete(rear2);
}
delete(rear1);
}
int main()
{
int n,a,b,c;
cin >> n;
Node* head = initial_link();
backlink(head, n);
cin >> a >> b >> c;
IsEmpty(head);
cout << endl;
printlink(head);
cout << endl;
cout << findlink(head, n)->data << endl;
insertlink(head, a, b);
printlink(head);
cout << endl;
deletelink(head, c);
printlink(head);
cout << endl;
destorylink(head);
IsEmpty(head);
return 0;
}
输入n,a,b,c,表示输入n个数,查找第n个数,在第a个数后插入b,删除第c个数
测试用例:n=5,a=4,b=9,c=1
结果:
4.双链表
双链表其实就是由有两个指针域的节点组成的链表,目的是为了能够访问前驱节点,以下是一个双链表节点的构成
data为该节点所存的数据,prior用于存放上一个节点的地址,next用于存放下一个节点的地址
因此一个节点可表示为:
struct DNode {
int data;
DNode* prior, * next;
};
数据域:data 指针域:prior,next
双链表的创建与单链表大体一致
双链表的初始化
DNode* initial_Dlink()
{
DNode* head = new DNode;
if (head == NULL)
{
cout << "分配失败,程序退出";
exit(-1);
}
head->next = NULL;
head->prior = NULL;
return head;
}
双链表求长
int Dlink_length(DNode* head)
{
DNode* rear = head->next;
int n = 0;
while (rear != NULL)
{
n++;
rear = rear->next;
}
return n;
}
双链表的尾插法
void backDlink(DNode* head, int n)//n为要传入链表数据的个数
{
DNode* rear = head;//这里依旧定义一个rear(用于指向插入节点的前一个节点),方便后续插入操作
int i;
for (i = 0; i < n; i++)
{
DNode* newnode = new DNode;
newnode->next = NULL;
newnode->prior=rear;//先对newnode操作
cin >> newnode->data;
rear->next = newnode;
rear = newnode;
}
}
头插法可参照单链表的头插法创建,这里就不在过多赘述
双链表的遍历
void printDlink(DNode* head)
{
DNode* rear = head->next;
while (rear != NULL)
{
cout << rear->data;
rear = rear->next;
}
}
//与单链表的遍历操作一模一样(水长度+1)😎
双链表是否为空的判断
void IsEmpty(DNode* head)
{
if (head->next == NULL)
{
cout << "true";
}
else
cout << "false";
}
双链表的查找
DNode* findDlink(DNode* head, int g)//查找第g个节点
{
if (g > Dlink_length(head))//判断g是否超出链表长度
{
cout << "不存在";
return NULL;
}
DNode* rear = head;
int i = 0;
while (i != g)
{
rear = rear->next;
i++;
}
return rear;
}
//还是和单链表的操作一模一样捏(水长度+2)😉
双链表由于prior的存在,因此还能采取二分的办法查找
双链表的查找(二分法)
DNode* findback(DNode* head)//在二分之前先找到尾节点
{
DNode* rear = head->next;
while (rear->next != NULL)
{
rear = rear->next;
}
return rear;
}
DNode* findDlink(DNode* head, DNode* back, int g)
{
if (g > Dlink_length(head))
{
cout << "ERROR";
return NULL;
}
else if (g > Dlink_length(head) / 2)//判断是否大于长度一半,大于则从尾节点开始查找
{
DNode* rear = back;
int i = Dlink_length(head);
while (i != g)
{
rear = rear->prior;
i--;
}
return rear;
}
else//从头节点开始查找
{
DNode* rear = head;
int i = 0;
while (i != g)
{
rear = rear->next;
i++;
}
return rear;
}
}
双链表的节点插入
void insertDlink(DNode* head, int g, int newdata)//在第g个节点后插入数据为newdata的新节点
{
if (g > Dlink_length(head))
{
cout << "ERROR";
return;
}
DNode* pre_newnode = findDlink(head, g);//调用查找
DNode* newnode = new DNode;
newnode->prior = pre_newnode;
newnode->next = pre_newnode->next;
newnode->data = newdata;
if (newnode->next != NULL)//这里要判断插入后的节点是否是最后一个节点
{
newnode->next->prior = newnode;
}
pre_newnode->next = newnode;
}
双链表的节点删除
void deleteDlink(Node* head, int g)
{
if (g > Dlink_length(head))
{
cout << "ERROR";
return;
}
DNode* deletenode = findlink(head, g);//由于prior的存在,因此不用定义pre_deletenode
deletenode->prior->next = deletenode->next;
if (deletenode->next != NULL)//判断删除的节点是否是最后一个节点
{
deletenode->next->prior = deletenode->prior;
}
delete(deletenode);
}
双链表的销毁同单链表的销毁,只不过更加简化,代码就不水了单独列出来了😎
最后完整代码
#include<bits/stdc++.h>
using namespace std;
struct DNode {
int data;
DNode* prior, * next;
};
DNode* initial_Dlink()
{
DNode* head = new DNode;
if (head == NULL)
{
cout << "分配失败,程序退出";
exit(-1);
}
head->next = NULL;
head->prior = NULL;
return head;
}
int Dlink_length(DNode* head)
{
DNode* rear = head->next;
int n = 0;
while (rear != NULL)
{
n++;
rear = rear->next;
}
return n;
}
void backDlink(DNode* head, int n)
{
DNode* rear = head;
int i;
for (i = 0; i < n; i++)
{
DNode* newnode = new DNode;
newnode->next = NULL;
newnode->prior = rear;
cin >> newnode->data;
rear->next = newnode;
rear = newnode;
}
}
void printDlink(DNode* head)
{
DNode* rear = head->next;
while (rear != NULL)
{
cout << rear->data;
rear = rear->next;
}
}
void IsEmpty(DNode* head)
{
if (head->next == NULL)
{
cout << "true";
}
else
cout << "false";
}
DNode* findDlink(DNode* head, int g)
{
if (g > Dlink_length(head))
{
cout << "不存在";
return NULL;
}
DNode* rear = head;
int i = 0;
while (i != g)
{
rear = rear->next;
i++;
}
return rear;
}
void insertDlink(DNode* head, int g, int newdata)
{
if (g > Dlink_length(head))
{
cout << "ERROR";
return;
}
DNode* pre_newnode = findDlink(head, g);
DNode* newnode = new DNode;
newnode->prior = pre_newnode;
newnode->next = pre_newnode->next;
newnode->data = newdata;
if (newnode->next != NULL)
{
newnode->next->prior = newnode;
}
pre_newnode->next = newnode;
}
void deleteDlink(DNode* head, int g)
{
if (g > Dlink_length(head))
{
cout << "ERROR";
return;
}
DNode* deletenode = findDlink(head, g);
deletenode->prior->next = deletenode->next;
if (deletenode->next != NULL)
{
deletenode->next->prior = deletenode->prior;
}
delete(deletenode);
}
void destoryDlink(DNode* head)
{
DNode* rear = head;//由于prior的存在,不需要定义rear2来辅助
while (rear ->next != NULL)
{
rear = rear->next;
delete(rear->prior);
}
delete(rear);
head->next = NULL;
}
int main()
{
int n, a, b, c;
cin >> n;
DNode* head = initial_Dlink();
backDlink(head, n);
cin >> a >> b >> c;
IsEmpty(head);
cout << endl;
printDlink(head);
cout << endl;
cout << findDlink(head, n)->data << endl;
insertDlink(head, a, b);
printDlink(head);
cout << endl;
deleteDlink(head, c);
printDlink(head);
cout << endl;
destoryDlink(head);
IsEmpty(head);
return 0;
}
//怎么有种套娃的感觉φ(* ̄0 ̄)
输入n,a,b,c,表示输入n个数,查找第n个数,在第a个数后插入b,删除第c个数
测试用例:n=6,a=3,b=1,c=2
结果:
5.循环链表
循环链表分为单向循环链表和双向循环链表,其实际上就是将最后一个节点的指针域和第一个节点相连,这样改造的好处是无论从任意节点进入链表,都能通过循环访问到任意一个节点
因此实现上并不困难,直接上代码(以循环单链表为例)
循环链表的初始化
Node* initial_looplink()
{
Node* head = new Node;
if (head == NULL)
{
cout << "分配失败,程序退出";
exit(-1);
}
head->next = NULL;
return head;
}
循环链表求长
int looplink_length(Node* head)
{
if (head->next == NULL)//判断链表是否为空
{
return 0;
}
Node* rear = head->next;
int n = 0;
do
{
rear = rear->next;
n++;
} while (rear != head->next);
return n;
}
循环链表的尾插法
void backlooplink(Node* head, int n)
{
Node* rear = head;
int i;
for (i = 0; i < n; i++)
{
Node* newnode = new Node;
newnode->next = head->next;//将原本的NULL换成第一个节点
cin >> newnode->data;
rear->next = newnode;
rear = newnode;
}
}
循环链表的遍历
void printlooplink(Node* head)
{
if (head->next == NULL)//判断链表是否为空
{
return;
}
Node* rear = head->next;
do//用do...while确保第一个节点能够输出
{
cout << rear->data;
rear = rear->next;
} while (rear != head->next);//注意判断条件的改变
}
循环链表是否为空的判断
void IsEmpty(Node* head)
{
if (head->next == NULL)//判断第一个节点是否为NULL
{
cout << "true";
}
else
cout << "false";
}
循环链表的查找
Node* findlooplink(Node* head, int g_data)//因为是循环链表,所以没必要查找第几个节点,因此我们查找数据为g_data的节点
{
Node* rear = head;
do
{
rear = rear->next;
} while (rear->data != g_data && rear->next != head->next);//防止陷入死循环
if (rear->data == g_data)
{
return rear;
}
else
{
cout << "不存在";
return NULL;
}
}
循环链表的节点插入
void insertlooplink(Node* head,int g_data,int newdata)//在数据为g_data的节点后插入数据为newdata的新节点
{
Node* pre_newnode=findlooplink(head, g);//调用链表的查找
if (pre_newnode == NULL)
{
cout << "ERROR";
return;
}
Node *newnode = new Node;
newnode->next =pre_newnode->next;
newnode->data = newdata;
pre_newnode->next = newnode;
}
//代码基本直接copy单链表的就好😋
循环链表的节点删除
void deletelooplink(Node* head, int g_data)//删除数据为g_data的节点
{
Node* deletenode = findlooplink(head, g_data);//查找该节点
if (deletenode == NULL)
{
cout << "ERROR";
return;
}
if (deletenode == head->next)//判断是否为第一个节点(因为第一个节点与尾节点相连)
{
if (looplink_length(head) == 1)//判断此时是否只剩下一个节点
{
delete(deletenode);
head->next = NULL;//删除,标记此链表为空
return;
}
Node* rear = head->next;
while (rear->next != head->next)//查找尾节点
{
rear = rear->next;
}
head->next = deletenode->next;//头节点的next也要改变
rear->next = deletenode->next;//改变尾节点next
return;
}
Node* pre_deletenode = head;
while (pre_deletenode->next != deletenode)
{
pre_deletenode = pre_deletenode->next;
}
pre_deletenode->next = deletenode->next;
delete(deletenode);//释放内存
}
循环链表的销毁
void destorylooplink(Node* head)
{
Node* rear1 = head->next;//这里让rear1先从第一个节点出发
Node* rear2 = NULL;//依旧定义两个rear,rear1负责向后遍历,rear2负责释放内存
do
{
rear2 = rear1;
rear1 = rear1->next;
delete(rear2);
} while (rear1 != head->next);
head->next = NULL;
}
完整代码
#include<bits/stdc++.h>
using namespace std;
struct Node {
int data;
Node* next;
};
Node* initial_looplink()
{
Node* head = new Node;
if (head == NULL)
{
cout << "分配失败,程序退出";
exit(-1);
}
head->next = NULL;
return head;
}
int looplink_length(Node* head)
{
if (head->next == NULL)
{
return 0;
}
Node* rear = head->next;
int n = 0;
do
{
rear = rear->next;
n++;
} while (rear != head->next);
return n;
}
void backlooplink(Node* head, int n)
{
Node* rear = head;
int i;
for (i = 0; i < n; i++)
{
Node* newnode = new Node;
newnode->next = head->next;
cin >> newnode->data;
rear->next = newnode;
rear = newnode;
}
rear->next = head->next;
}
void printlooplink(Node* head)
{
if (head->next == NULL)
{
return;
}
Node* rear = head->next;
do
{
cout << rear->data;
rear = rear->next;
} while (rear != head->next);
}
void IsEmpty(Node* head)
{
if (head->next == NULL)
{
cout << "true";
}
else
cout << "false";
}
Node* findlooplink(Node* head, int g_data)
{
Node* rear = head;
do
{
rear = rear->next;
} while (rear->data != g_data && rear->next != head->next);
if (rear->data == g_data)
{
return rear;
}
else
{
cout << "不存在"<<endl;
return NULL;
}
}
void insertlooplink(Node* head, int g_data, int newdata)
{
Node* pre_newnode = findlooplink(head, g_data);
if (pre_newnode == NULL)
{
cout << "ERROR";
return;
}
Node* newnode = new Node;
newnode->next = pre_newnode->next;
newnode->data = newdata;
pre_newnode->next = newnode;
}
void deletelooplink(Node* head, int g_data)
{
Node* deletenode = findlooplink(head, g_data);
if (deletenode == NULL)
{
cout << "ERROR";
return;
}
if (deletenode == head->next)
{
if (looplink_length(head) == 1)
{
delete(deletenode);
head->next = NULL;
return;
}
Node* rear = head->next;
while (rear->next != head->next)
{
rear = rear->next;
}
head->next = deletenode->next;
rear->next = deletenode->next;
return;
}
Node* pre_deletenode = head;
while (pre_deletenode->next != deletenode)
{
pre_deletenode = pre_deletenode->next;
}
pre_deletenode->next = deletenode->next;
delete(deletenode);
}
void destorylooplink(Node* head)
{
Node* rear1 = head->next;
Node* rear2 = NULL;
do
{
rear2 = rear1;
rear1 = rear1->next;
delete(rear2);
} while (rear1 != head->next);
head->next = NULL;
}
int main()
{
int n, a, b, c;
cin >> n;
Node* head = initial_looplink();
backlooplink(head, n);
cin >> a >> b >> c;
IsEmpty(head);
cout << endl;
printlooplink(head);
cout << endl;
insertlooplink(head, a, b);
printlooplink(head);
cout << endl;
deletelooplink(head, c);
printlooplink(head);
cout << endl;
destorylooplink(head);
IsEmpty(head);
return 0;
}
输入n,a,b,c,表示输入n个数,在数据为a的数后插入b,删除数据为c的数
测试用例:n=8,a=3,b=9,c=1
结果:
结语:
新手第一次写blog,写的不好的话还请见谅😭(;´д`)ゞ