单链表
简介
什么是单链表
单链表(Singly Linked List)是用一组任意的存储单元存放线性表的元素,单链表的存在可以让我们能够在常数时间复杂度内完成查找操作。
单链表的特点
单链表中的每个结点不仅包含值,还包含链接到下一个结点的引用字段。
通过这种方式,单链表将所有节点按顺序组织起来。
与数组不同,我们无法在常量时间内访问单链表中的随即元素。如果我们想要获得第i各元素,必须从头结点逐个遍历。
按索引来访问元素的平均时间复杂度为O(N) N为链表的长度
单链表的操作
单链表结点的定义与设计
struct Node
{
int val; //数据域
Node* next; //后继节点
Node(int newVal):val(newVal),next(nullptr) {}
};
Node(int newVal):val(newVal),next(nullptr) {}
这一行相当于默认构造函数
为新结点的val数据与赋值为newVal 后继结点默认置为空指针nullptr
操作的设计模式
单链表操作的设计模式是统一的。
一般有一个工作指针和一个累加器作为条件去进行判断和遍历。
在我的代码中你会经常能够看到workNode和count两个变量。
单链表的添加操作
如果想在给定的结点prev之后添加新值,我们应该:
其中 prev–previous 之前 cur-current 当前 next 下一个
1、使用给定值初始化新结点cur
2、将cur的next字段链接到prev的下一个结点next
3、将prev的next字段链接到cur
单链表的删除操作
如果我们想从单链表中删除现有结点cur,分两步
1、找到cur的上一个结点prev及其下一个结点next
2、链接prev到cur的下一个结点next
根据添加和删除操作的设计模式,你应该能够理解其余的算法设计模式!
单链表的设计
单链表类的设计 LinkedList
//手撕单向链表
class LinkedList
{
private:
struct Node
{
int val; //数据域
Node* next; //后继节点
Node(int newVal):val(newVal),next(nullptr) {}
};
Node* head; //头指针应该置空
int size;
public:
LinkedList();
~LinkedList();
void addAtTail(int newVal); //添加到尾节点之后
void addAtSomeWhere(int index,int newVal); //添加到指定位置
void printList(); //遍历输出链表的所有值
int get(int index); //获得指定位置的链表值
void deleteByIndex(int index); //删除指定位置的元素
int length(); //返回单向链表的长度 不包含头部节点
void mySort(); //单向链表排序
};
单链表操作的实现
构造函数
LinkedList::LinkedList()
{
cout<<"---初始化链表---"<<endl;
this->head=new Node(1e9);
this->size++;
}
析构函数
析构函数要删除链表的所有结点
LinkedList::~LinkedList()
{
Node* workNode=head;
while(head!=nullptr)
{
head=head->next;
delete workNode;
workNode=head;
}
this->size=0;
}
尾部添加
void LinkedList::addAtTail(int newVal)
{
//添加到尾节点后面
Node* workNode=new Node(0);
Node* newNode=new Node(newVal);
workNode=head;
for(int i=0;i<size;i++)
{
if(workNode->next!=nullptr)
{
workNode=workNode->next;
}
}
workNode->next=newNode;
this->size++;
}
添加到指定位置
void LinkedList::addAtSomeWhere(int index,int newVal)
{
//插入元素到指定位置
Node* workNode=head; //工作指针 用于游历链表
int count=0; //计数器
while(workNode!=nullptr && count<index-1)
{
//定位到传入索引的前一个结点
workNode=workNode->next;
count++;
}
if(workNode==nullptr) //如过找不到
{
throw "传入索引位置错误";
}
else
{
Node* newNode=new Node(newVal);
newNode->next=workNode->next;
workNode->next=newNode;
}
}
有没有看到我定义的工作指针和计数累加器?
这就是链表操作的设计模式
找准循环条件 多用while 少用for
先定位到前一个结点 也就是 prev
遍历链表
void LinkedList::printList()
{
//遍历链表
Node* workNode=new Node(0);
workNode=head->next;
while(workNode!=nullptr)
{
cout<<workNode->val<<" ";
workNode=workNode->next;
}
cout<<endl;
}
获得指定位置的元素值
int LinkedList::get(int index)
{
//获得指定位置的数据
Node* workNode=head;
int count=0; //累加器初始化
while(workNode!=nullptr && count<index)
{
workNode=workNode->next;
count++;
}
if(workNode==nullptr)
{
throw "索引错误";
}
else
{
return workNode->val;
}
}
删除指定位置的元素
void LinkedList::deleteByIndex(int index)
{
//删除指定位置的元素
Node* workNode=head;
Node* temp=new Node(0); //存储要被删除的结点
int count=0;
while(workNode!=nullptr && count<index-1)
{
//定位到前一个结点
workNode=workNode->next;
count++;
}
if(workNode==nullptr)
{
throw "位置错误";
}
else
{
temp=workNode->next; //清除内存
workNode->next=workNode->next->next;
}
delete temp;
}
记得要删除结点 清理内存
获得链表长度(不含头结点)
int LinkedList::length()
{
Node* workNode=head;
int length=0;
while(workNode->next!=nullptr)
{
workNode=workNode->next;
length++;
}
return length;
}
排序
void LinkedList::mySort()
{
//排序算法
//大致思路 先将所有元素存储到vector中 再使用vector的排序算法进行排序
//遍历链表
Node* workNode=new Node(0);
vector<int> v1;
workNode=head->next;
while(workNode!=nullptr)
{
v1.push_back(workNode->val);
workNode=workNode->next;
}
sort(v1.begin(),v1.end());
workNode=head->next;
int count=0;
while(workNode!=nullptr)
{
workNode->val=v1[count];
workNode=workNode->next;
count++;
}
cout<<v1.size()<<endl;
}
algorithm库内置排序算法
sort(vector.begin(),vector.end());
完整代码
LinkedList.h
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
/*
*Author:YiXing Liu
*Date:2021
*Des:Singly Linked List
*/
//手撕单向链表
class LinkedList
{
private:
struct Node
{
int val; //数据域
Node* next; //后继节点
Node(int newVal):val(newVal),next(nullptr) {}
};
Node* head; //头指针应该置空
int size;
public:
LinkedList();
~LinkedList();
void addAtTail(int newVal); //添加到尾节点之后
void addAtSomeWhere(int index,int newVal); //添加到指定位置
void printList(); //遍历输出链表的所有值
int get(int index); //获得指定位置的链表值
void deleteByIndex(int index); //删除指定位置的元素
int length(); //返回单向链表的长度 不包含头部节点
void mySort(); //单向链表排序
};
LinkedList.cpp
#include "LinkedList.h"
LinkedList::LinkedList()
{
cout<<"---初始化链表---"<<endl;
this->head=new Node(1e9);
this->size++;
}
LinkedList::~LinkedList()
{
Node* workNode=head;
while(head!=nullptr)
{
head=head->next;
delete workNode;
workNode=head;
}
this->size=0;
}
void LinkedList::addAtTail(int newVal)
{
//添加到尾节点后面
Node* workNode=new Node(0);
Node* newNode=new Node(newVal);
workNode=head;
for(int i=0;i<size;i++)
{
if(workNode->next!=nullptr)
{
workNode=workNode->next;
}
}
workNode->next=newNode;
this->size++;
}
void LinkedList::addAtSomeWhere(int index,int newVal)
{
//插入元素到指定位置
Node* workNode=head; //工作指针 用于游历链表
int count=0; //计数器
while(workNode!=nullptr && count<index-1)
{
//定位到传入索引的前一个结点
workNode=workNode->next;
count++;
}
if(workNode==nullptr)
{
throw "传入索引位置错误";
}
else
{
Node* newNode=new Node(newVal);
newNode->next=workNode->next;
workNode->next=newNode;
}
}
void LinkedList::printList()
{
//遍历链表
Node* workNode=new Node(0);
workNode=head->next;
while(workNode!=nullptr)
{
cout<<workNode->val<<" ";
workNode=workNode->next;
}
cout<<endl;
}
int LinkedList::get(int index)
{
//获得指定位置的数据
Node* workNode=head;
int count=0; //累加器初始化
while(workNode!=nullptr && count<index)
{
workNode=workNode->next;
count++;
}
if(workNode==nullptr)
{
throw "索引错误";
}
else
{
return workNode->val;
}
}
void LinkedList::deleteByIndex(int index)
{
//删除指定位置的元素
Node* workNode=head;
Node* temp=new Node(0); //存储要被删除的结点
int count=0;
while(workNode!=nullptr && count<index-1)
{
//定位到前一个结点
workNode=workNode->next;
count++;
}
if(workNode==nullptr)
{
throw "位置错误";
}
else
{
temp=workNode->next; //清除内存
workNode->next=workNode->next->next;
}
delete temp;
}
int LinkedList::length()
{
Node* workNode=head;
int length=0;
while(workNode->next!=nullptr)
{
workNode=workNode->next;
length++;
}
return length;
}
void LinkedList::mySort()
{
//排序算法
//大致思路 先将所有元素存储到vector中 再使用vector的排序算法进行排序
//遍历链表
Node* workNode=new Node(0);
vector<int> v1;
workNode=head->next;
while(workNode!=nullptr)
{
v1.push_back(workNode->val);
workNode=workNode->next;
}
sort(v1.begin(),v1.end());
workNode=head->next;
int count=0;
while(workNode!=nullptr)
{
workNode->val=v1[count];
workNode=workNode->next;
count++;
}
cout<<v1.size()<<endl;
}
testList.cpp 测试
#include"LinkedList.h"
using namespace std;
int main()
{
cout<<"Hello"<<endl;
cout<<"你好"<<endl;
LinkedList l1;
l1.addAtTail(3);
l1.addAtSomeWhere(2,4);
l1.addAtTail(8);
l1.addAtSomeWhere(3,6);
l1.printList();
cout<<"长度为"<<l1.length()<<endl;
cout<<l1.get(2)<<endl;
l1.deleteByIndex(2);
l1.addAtSomeWhere(2,9);
l1.printList();
cout<<"长度为"<<l1.length()<<endl;
l1.mySort();
l1.printList();
system("pause");
return 0;
}
后记
测试代码写的不是很详细
你可以自己使用try…catch…去写一下
排序算法写的略复杂
你看看你自己能不能手撕一个链表的冒泡排序出来
防卫式声明也没来得及和你讲
回去教你
谨记
见字如面
勿念