经历了两天的理解,终于弄明白了链表List的底层逻辑,便是定义结构体,给结构体附上value值和下一个节点的指针,我不禁想 是否所有的 数据结构 都可以用struct来定义呢?我不着急知道答案,而是会循序渐进,弄清楚代码的世界。
链表的构建 包含了几点:
1)节点的struct定义;
2)链表的定义 >> 链表的赋值操作;
3)对链表的操作;
首先, 节点 包含value值,由于节点不像数组一样是连续存储的,因此想要找到一个链表内的所有元素需要知道其所有元素的地址,而数组呢,只需要知道首地址以及数组的长度即可。
其次,链表的定义,链表大致分为两种 第一种是有头(空)节点的,第二种是没有头节点的,怎么去描述呢 没有头节点的就像一个结构体数组,包含了value值和next的地址,而有头(空)节点的相当于这数组前添加了一项,但它没有数值,只是包含了next的地址,因此在实际操作中要略过头节点。
最后 链表的操作,这里没什么好说的,类似于类与对象的操作,struct 结构体和 class 类 还是有很多相似之处的。
下面看构建链表的代码:
#include<iostream>
using namespace std;
struct Node {
int value;
Node* Next;
};
struct Node* List_creat(int a[], int n) {
Node* List = (Node*)malloc(sizeof(Node));
if (List == NULL) {
cout << "创建失败!";
return NULL;
}
Node* p = List;
for (int i = 0; i <= n - 1; i++) {
Node* temp = (Node*)malloc(sizeof(Node));
temp->value = a[i];
p->Next = temp;
p = p->Next;
}
p->Next = NULL;
return List;
}
void deletepos(Node* List, int pos);
void deletevalue(Node* List);
void display(Node* List);
int showmeposvalue(Node* List,int pos);
void insert_front(Node* List);
void insert_back(Node* List);
int main() {
int a[5] = { 1,2,3,4,5 };
int size = sizeof(a) / sizeof(a[0]);
Node *List = List_creat(a, 5);
display(List);
deletepos(List, 3);
display(List);
insert_front(List);
display(List);
cout << "Second pos's value:" << showmeposvalue(List, 2) << endl;
insert_back(List);
display(List);
deletevalue(List);
return 0;
}
void deletepos(Node* List, int pos) {
Node* current = List;
Node* temp = List->Next;
for (int i = 0; i <= pos - 2; i++) {
current = current->Next;
temp = temp->Next;
}
current->Next = temp->Next;
}
void display(Node* List) {
for (Node* p = List->Next; p; p = p->Next)
cout << p->value << " ";
cout << endl;
}
int showmeposvalue(Node* List,int pos) {
Node* position = List;
for (int i = 0; i <= pos - 1; i++)
position = position->Next;
return position->value;
}
void insert_front(Node* List) {
Node* temp = (Node*)malloc(sizeof(Node));
cout << "Please input new node's Value:";
cin >> temp->value;
temp->Next = List->Next;
List->Next = temp;
}
void insert_back(Node* List) {
Node* pos = NULL;
for (Node* p = List->Next; p; p = p->Next) {
pos = p;
};
Node* temp = (Node*)malloc(sizeof(Node));
cout << "Please input new node's Value:";
cin >> temp->value;
pos->Next = temp;
temp->Next = NULL;
}
void deletevalue(Node* List) {
int target;
cout << "Please input your target:";
cin >> target;
Node* current = List;
Node* temp = List->Next;
for (Node* p = List->Next; p; p = p->Next) {
if (p->value != target) {
current = current->Next;
temp = temp->Next;
}
else {
temp = temp->Next;
current->Next = temp;
current = current->Next;
}
}
display(List);
}
解析:
1.void deletepos(Node*List,int pos) 删除第 pos 项的节点
void deletepos(Node* List, int pos) {
Node* current = List;
Node* temp = List->Next;
for (int i = 0; i <= pos - 2; i++) {
current = current->Next;
temp = temp->Next;
}
current->Next = temp->Next;
}
此方法 适用于有头节点的链表,初始化 current 为头节点,temp为头节点.next 即实际链表的第一项,通过循环来移动两个指针,因为是用 temp 来记录第pos项的地址,又temp初始值为List.Next,所以循环条件为 i <= pos - 2 而不是 pos -1.得到了第 pos 项的地址后,将 pos 项 前一节点current所指向的节点变为temp.Next 操作为 current.Next=temp.Next 即可.
2.void display(Node*List) Talk is shit,show me code
void display(Node* List) {
for (Node* p = List->Next; p; p = p->Next)
cout << p->value << " ";
cout << endl;
}
这里仅需解释循环条件 for( Node*p=List.Next,p,p=p.Next)
首先定义一个结构体指针 p 指向链表头节点之后,即链表的第一项,循环条件是 p,p是啥呢 先不看条件,先看循环结束后的操作 p = p.Next,很容易理解 此操作是将 p 的指向下移,即遍历所有链表指针,再回头看循环条件,当循环到p = NULL,即循环到尾节点之后的 NULL 时退出循环,因为这时所有的链表元素已经被遍历结束了.循环体中只需要输出所有遍历的节点的value值即可.
3.int showmeposvalue(Node* List, int pos) 显示第 pos 项的 value 值
int showmeposvalue(Node* List, int pos) {
Node* position = List;
for (int i = 0; i <= pos - 1; i++)
position = position->Next;
return position->value;
}
遍历到第 pos 个节点输出其 value 值即可
4.void insert_front(Node* List) 在链表前插入一个节点
void insert_front(Node* List) {
Node* temp = (Node*)malloc(sizeof(Node));
cout << "Please input new node's Value:";
cin >> temp->value;
temp->Next = List->Next;
List->Next = temp;
}
这里的插入分两种情况,情况一对于没有 头节点 的链表来说,直接创建一个新的节点 赋值后指向链表的第一项即可,情况二是有 头节点 的链表 这里的增加就不是简单的在整个链表的最前方增加节点了,而是创建一个节点 先去指向链表的第一项 ,再将头节点指向这个新的节点,至此形成新的链表.
5.void insert_back(Node* List) 在链表后插入一个节点
void insert_back(Node* List) {
Node* pos = NULL;
for (Node* p = List->Next; p; p = p->Next) {
pos = p;
};
Node* temp = (Node*)malloc(sizeof(Node));
cout << "Please input new node's Value:";
cin >> temp->value;
pos->Next = temp;
temp->Next = NULL;
}
这里的添加 需要通过循环来找到链表的尾节点,再创建新节点并赋值后,将尾节点指向新节点 .
6.void deletevalue(Node* List) 删除链表内数值为value的节点
void deletevalue(Node* List) {
int target;
cout << "Please input your target:";
cin >> target;
Node* current = List;
Node* temp = List->Next;
for (Node* p = List->Next; p; p = p->Next) {
if (p->value != target) {
current = current->Next;
temp = temp->Next;
}
else {
temp = temp->Next;
current->Next = temp;
current = current->Next;
}
}
display(List);
}
这个。我解释不了 因为不知道为啥我写的代码只能删除一次该 value 的节点,哈哈
5.22 >> 5.23 24:00