链表简介
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,链表比较方便插入和删除操作。
类结构要素
class List {
public:
List() {
create_List();
}
~List() {
clear();
}
//打印
void print() {
for (Node * p = head->next; p; p = p->next) {
cout << p->data << " ";
}
cout << endl;
}
private:
//节点结构
struct Node {
int data;
Node * next;
Node(const int& d) : data(d), next(NULL) {
}
};
Node *head;//头节点
//清理链表函数
void clear() {
Node * p = head;
while (p) { //从头节点开始循环删除
Node * q = p->next;
delete p;
p = q;
}
}
};
基本操作
创建头结点
手动new一个新的Node,将Node的next置为NULL即可。
//创建头结点
void create_List() {
head = new Node(0);
}
从头插入一个新的节点
手动new出一个新的节点p,使p的next的指向head->next所指向的地址,然后将head->next从新指向p即可。
//从头插入一个节点
void insert(const int& d) {
Node *p = new Node(d);
p->next = head->next;
head->next = p;
}
删除指定节点
先遍历到指定节点的前一个节点,然后通过将前一个节点的next指针指向指定节点的下一个节点,达到悬空指定节点的效果,然后删除指定节点即可。
//删除指定数据的节点
void erase(const int& d) {
Node * p = find(d);
Node *q = p->next;//因为p是上一个节点的位置,用q来保存要删除的节点的地址
p->next = p->next->next;//通过将上一个节点的next指针指向要删除节点的next实现断开要删除节点的目的
delete q;//删除
}
修改指定节点
遍历到指定节点的位置,将其data修改为要修改的值即可。
//修改指定数据
void updata(const int& d, const int& d1) {
Node * p = find(d);
p->next->data = d1;
}
指定节点值后插入节点
查找链表指定值,在该值后插入节点。
//指定位置插入节点
void insert_pos(const int& d, const int& d1)
{
Node * p = find(d);
Node * q = new Node(d1);
q->next = p->next;
p->next = q;
}
查找指定节点值得前驱节点
指定一个节点值,找到该节点的前面一个节点。
//查找数据d的上一个节点位置的函数,便于后面删除操作
Node* find(const int& d) {
Node * p = head;
for (; p; p = p->next) {
if (p->next->data == d) {
break;
}
}
return p;
}
进阶操作
反转
步骤:
1、临时保存头节点后的第二个节点q的q->next;
2、q->next指向q的前一个节点;
3、p指针后移以为,q指针后移一位;
重复步骤1-3直到链表尾部。
4、头指针重新指向新的的第1个节点。
//反转链表
void reverse() {
Node *p = head->next;//头结点之后的第1个节点
Node *q = head->next->next;//头结点之后的第2节点
Node *temp;
p->next = NULL;//将头接点之后的第1个节点的next指针置为空
while (q->next) {//根据q->next是否为空来判断 以此逆序每一个节点
temp = q->next;
q->next = p;
p = q;
q = temp;
}
q->next = p;//将最后一个节点逆序
head->next = q;//将头重新指向新的的第1个节点(之前的最后一个节点)
}
反向遍历
从尾部向头部遍历。借助栈,正向遍历,将节点值入栈,最后出栈即可。
//反向遍历
void reversePrint() {
if (head->next == nullptr) {
return;
}
//创建栈
stack<int> stack1;
//遍历指针
Node *temp = head->next;
while (temp != nullptr) {
stack1.push(temp->data);
temp = temp->next;
}
//打印栈中的数据
while (!stack1.empty()) {
cout << stack1.top() << " ";
stack1.pop();
}
cout << endl;
}
冒泡排序
节点值交换法
符合条件即交换节点值。
//节点值交换法
void SortVal() {
Node *p, *q;
int n_temp = 0;
for (p = head->next; p != nullptr; p = p->next) {
for (q = p->next; q != nullptr; q = q->next) {
if (p->data > q->data)//根据学号从小到大排序
{
n_temp = p->data;
p->data = q->data;
q->data = n_temp;
}
}
}
}
节点交换法
符合条件即交换节点,交换分两种情况:
1、两个节点不相邻;
2、两个节点相邻。
交换思想:先临时保存后一个节点p的p->next,再交换两个节点即可。
void Sort() {
Node *p, *q, *p_temp;
Node *p_pre = head, *q_pre = head->next;
for (p = head->next; p != nullptr; p = p->next) {
for (q = p->next; q != nullptr; q = q->next) {
if (p->data > q->data && p->next != q) { //p,q节点不相邻
p_temp = q->next;
p_pre->next = q;
q->next = p->next;
q_pre->next = p;
p->next = p_pre;
}
else if (p->data > q->data && p->next == q) { //p,q节点相邻
p_temp = q->next;
p_pre->next = q;
q->next = p;
p->next = p_temp;
}
q_pre = q;
}
p_pre = p;
}
}