链表
1 基础基础
1.1 链表理论基础
- 头指针
- 头结点
- 首元结点
相关文章: 链表理论基础 - Status
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
Status函数的返回值是这六种类型的数
1.2 链表构造函数
struct LinkNode{
int val;
LinkNode* next;
LinkNode(int val):val(val),next(nullptr){}
};
LinkNode(int val):val(val),next(nullptr){} 是构造函数初始化列表。以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式,初始化列表仅在构造函数中有效,不能用于其他函数,可以初始化任何数据成员,包括其他办法不能初始化的const成员。
初始化列表,他们会在构造函数正式调用前被调用 ,且他们的初始化顺序并不是根据 初始化列表中出现的顺序,而是他们声明的顺序来初始化。
相关文章1: 构造函数初始化列表
相关文章2: const成员初始化详解
1.3 NULL和nullptr
相关文章: NULL和nullptr
2 移除链表元素
2.1 无头结点进行移除节点操作
直接使用原来的链表来进行移除节点操作。
- 主要代码
class Solution{
public:
ListNode* removeElements(ListNode* head,int val){
//删除首元结点
while(head != NULL && head->val == val){
ListNode* tmp = head;
head = head->next;
delete tmp;
}
//删除非头结点
ListNode* cur = head;
while(cur != NULL && cur->next != NULL){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else
cur = cur->next;
}
return head;
}
};
- 运行代码
#include<iostream>
#include<cstdio>
using namespace std;
struct ListNode{
int val;
ListNode *next;
ListNode(int x): val(x),next(NULL) {}
};
int count = 0;
ListNode* InitList(){
ListNode *head;
ListNode *q,*p;
head = (ListNode *)malloc(sizeof(ListNode));
q = head;
while(1)
{
count++;
p = (ListNode *)malloc(sizeof(ListNode));
printf("请输入第%d个数:(如需结束输入-99999): ",count);
scanf("%d",&p->val);
if(p->val==-99999){
return head;
}
p->next = NULL;
q->next = p;
q = p;
}
}
void showList(ListNode* m){
ListNode* p;
p = m->next;
while(p!=NULL)
{
printf("%d ",p->val);
p = p->next;
}
}
class Solution{
public:
ListNode* removeElements(ListNode* head,int val){
//删除头结点
while(head != NULL && head->val == val){
ListNode* tmp = head;
head = head->next;
delete tmp;
}
//删除非头结点
ListNode* cur = head;
while(cur != NULL && cur->next != NULL){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else
cur = cur->next;
}
return head;
}
};
int main()
{
Solution s;
ListNode *m = InitList();
printf("请输入要删除的元素: ");
int val;
cin >> val;
s.removeElements(m,val);
showList(m);
return 0;
}
2.2 头结点进行移除节点操作
给链表添加一个头结点,使得能够将对首元结点的操作与其他结点统一。
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0); // 设置一个头结点
dummyHead->next = head; // 将头结点指向head,这样方面后面做删除操作
ListNode* cur = dummyHead;
while (cur->next != NULL) {
if(cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
3 设计链表
3.1 return
return;//不带返回值的return语句
return 0;//带返回值的return语句,或者返回一个变量或一个函数。
return;的作用相当于break;用于中断循环的作用,而return 0;则是return的另一种用法,专用于返回值非void的函数返回其值。
3.2 get和set方法
要想访问私有数据域,要使用get方法,修改私有数据域要使用set方法。
private:
int _size;
LinkedNode* _dummyHead;
};
int getSize(void){
return _size;
}
相关文章: C++访问私有成员变量(private)的常用方法
3.3 主要代码
struct LinkedNode{
int val;
LinkedNode* next;
LinkedNode(int val):val(val),next(nullptr){};//构造函数初始化列表
};
class MyLinkedList{
public:
//初始化链表,默认构造函数
MyLinkedList(){
_dummyHead = new LinkedNode(0);//头结点
_dummyHead -> next = NULL;
}
//获取第index个结点数值
int get(int index){
if(index > (_size - 1) || index < 0){
return -1;
}
LinkedNode* cur = _dummyHead -> next;
while(index--){
cur = cur ->next;
}
return cur -> val;
}
//头插法 插一个结点
void addAtHead(int val){
LinkedNode* newNode = new LinkedNode(val);
newNode-> next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
//尾插法 插一个结点
void addAtTail(int val){
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newNode;
_size++;
}
void addIndex(int index,int val){
if(index > _size) return;
if(index < 0) index = 0;
LinkedNode* newNode = new LinkedNode (val);
LinkedNode* cur = _dummyHead;
while(index--){
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
void deleteAtIndex(int index){
if(index >= _size || index < 0){
return;
}
LinkedNode* cur = _dummyHead;
while(index--){
cur = cur->next;
}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}
void printLinkedList(){
LinkedNode* cur = _dummyHead;
while(cur->next!=nullptr){
cout << cur->next->val<<" ";
cur = cur->next;
}
cout << endl;
}
int getSize(void){
return _size;
}
private:
int _size;
LinkedNode* _dummyHead;
};
3.4 可运行代码
#include<iostream>
#include<cstdio>
using namespace std;
struct LinkedNode{
int val;
LinkedNode* next;
LinkedNode(int val):val(val),next(nullptr){};//构造函数初始化列表
};
class MyLinkedList{
public:
//初始化链表,默认构造函数
MyLinkedList(){
_dummyHead = new LinkedNode(0);//头结点
_size = 0;
}
//获取第index个结点数值
int get(int index){
if(index > (_size - 1) || index < 0){
return -1;
}
LinkedNode* cur = _dummyHead -> next;
while(index--){
cur = cur ->next;
}
return cur -> val;
}
//头插法 插一个结点
void addAtHead(int val){
LinkedNode* newNode = new LinkedNode(val);
newNode-> next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
//尾插法 插一个结点
void addAtTail(int val){
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newNode;
_size++;
}
void addIndex(int index,int val){
if(index > _size) return;
if(index < 0) index = 0;
LinkedNode* newNode = new LinkedNode (val);
LinkedNode* cur = _dummyHead;
while(index--){
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
void deleteAtIndex(int index){
if(index >= _size || index < 0){
return;
}
LinkedNode* cur = _dummyHead;
while(index--){
cur = cur->next;
}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}
void printLinkedList(){
LinkedNode* cur = _dummyHead;
while(cur->next!=nullptr){
cout << cur->next->val<<" ";
cur = cur->next;
}
cout << endl;
}
int getSize(void){
return _size;
}
private:
int _size;
LinkedNode* _dummyHead;
};
int main()
{
MyLinkedList a;
a.addAtHead(5);
a.addAtTail(6);
a.printLinkedList();
a.deleteAtIndex(1);
int _size = a.getSize();
a.printLinkedList();
cout << _size << endl;
return 0;
}
4 反转链表
4.1 双指针法
首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。
然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。
为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。
接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。
最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。
4.1.1 主要代码
ListNode* reverseList(ListNode* head) {
ListNode* temp; // 保存cur的下一个节点
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur->next = pre; // 翻转操作
// 更新pre 和 cur指针
pre = cur;
cur = temp;
}
return pre;
}
4.1.2 运行代码
//反转链表
//双指针法
#include<iostream>
#include<cstdio>
using namespace std;
struct ListNode{
int val;
ListNode *next;
ListNode(int x): val(x),next(NULL) {}
};
class Solution{
public:
Solution(){
_dummyHead = new ListNode(0);//头结点
_size = 0;
}
void addAtHead(int val){
ListNode* newNode = new ListNode(val);
newNode-> next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
void printLinkedList(){
ListNode* cur = _dummyHead;
while(cur->next!=nullptr){
cout << cur->next->val<<" ";
cur = cur->next;
}
cout << endl;
}
void printLinkedList1(ListNode* c){
ListNode* cur = c;
while(cur!=nullptr){
cout << cur->val<<" ";
cur = cur->next;
}
cout << endl;
}
//没有头结点
ListNode* reverseList(ListNode* head) {
ListNode* temp; // 保存cur的下一个节点
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur->next = pre; // 翻转操作
// 更新pre 和 cur指针
pre = cur;
cur = temp;
}
return pre;
}
ListNode* getHead(void){
return _dummyHead;
}
private:
ListNode* _dummyHead;
int _size;
};
int main()
{
Solution m;
m.addAtHead(5);
m.addAtHead(6);
m.addAtHead(7);
m.printLinkedList();
ListNode* _dummyHead = m.getHead();
ListNode* c = m.reverseList(_dummyHead->next);
m.printLinkedList1(c);
return 0;
}
完成可运行代码的过程中出现了很多问题:
- 注意之前所写的addAtHead是针对有头结点的,printLinkedList也是针对有头结点的链表,而这道题是没有头结点的,所以在使用函数时,要注意是ListNode* c = m.reverseList(_dummyHead->next)。并且print时要修改,本文我重新写了printLinkedList1()函数专门用来打印反转链表。
4.2 递归
4.2.1 主要代码
ListNode* reverse(ListNode* cur,ListNode* pre){
if(cur==NULL) return pre;
ListNode* temp = cur->next;
cur->next = pre;//反转
return reverse(temp,cur);
}
ListNode* reverseList(ListNode* head){
return reverse(head,NULL);
}
4.2.1 运行代码
//反转链表,递归法
#include<iostream>
#include<cstdio>
using namespace std;
struct ListNode{
int val;
ListNode *next;
ListNode(int x): val(x),next(NULL) {}
};
class Solution{
public:
Solution(){
_dummyHead = new ListNode(0);//头结点
_size = 0;
}
void addAtHead(int val){
ListNode* newNode = new ListNode(val);
newNode-> next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
void printLinkedList(){
ListNode* cur = _dummyHead;
while(cur->next!=nullptr){
cout << cur->next->val<<" ";
cur = cur->next;
}
cout << endl;
}
void printLinkedList1(ListNode* c){
ListNode* cur = c;
while(cur!=nullptr){
cout << cur->val<<" ";
cur = cur->next;
}
cout << endl;
}
//没有头结点
ListNode* reverse(ListNode* cur,ListNode* pre){
if(cur==NULL) return pre;
ListNode* temp = cur->next;
cur->next = pre;//反转
return reverse(temp,cur);
}
ListNode* reverseList(ListNode* head){
return reverse(head,NULL);
}
ListNode* getHead(void){
return _dummyHead;
}
private:
ListNode* _dummyHead;
int _size;
};
int main()
{
Solution m;
m.addAtHead(5);
m.addAtHead(6);
m.addAtHead(7);
m.printLinkedList();
ListNode* _dummyHead = m.getHead();
ListNode* c = m.reverseList(_dummyHead->next);
//需要改变打印方式,不满足之前有头结点的打印方式了
m.printLinkedList1(c);
return 0;
}