链表的定义
struct ListNode
{
int val;
ListNode *next;
ListNode():val(0),next(nullptr);
ListNode(int x):val(x),next(nullptr);
}
1.链表的初始化
ListNode * head=new ListNode(5);//创建1个头结点:val值为5
2.构建链表类
class Mylist
{
struct ListNode
{
int val;
ListNode *next;
ListNode():val(0),next(nullptr);
ListNode(int x):val(x),next(nullptr);
};
Mylist()
{
// 构造一个虚拟的头结点
dumpy_head=new ListNode(-1);
// 链表的大小
_size =0;
}
private:
ListNode *dumpy_head;
int _size;
3.链表的头插(先连接后面,再连接前面)
- 创建新节点
- 新节点的next 指向原本的结点
- 虚拟结点指向新节点
- 结点的个数要加1
void addAtHead(int val)
{
ListNode *newNode =new ListNode(val);
newNode->next=dumpy_head->next;
dumpy_head->next =newNode;
_size ++;
}
4.链表的尾插: 结点的个数要加1
void addAtTail(int val) {
ListNode * cur=dumpy_head->next;
while(cur->next !=nullptr)
{
cur=cur->next;
}
ListNode *newNode =new ListNode(val);
cur->next =newNode;
_size ++;
5.链表的反转:给定一个链表1-2-3-4-5,要求在原链表的基础上反转链表。
链表的反转
这类题目最好的方法是画图:
双指针的方法:
给定前驱指针(prev),当前指针(cur),需要反转的下一个指针tmp=cur->next(否则反转之后的话就找不到下一个结点了)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev =nullptr;
ListNode* cur=head;
while(cur!=nullptr)
{
// 保存下一个需要翻转的结点
ListNode *tmp=cur->next;
// 当前结点的下一个结点指向前驱结点
cur->next =prev;
// prev和cur依次向后移动
prev =cur;
cur =tmp;
}
return head;
}
6.链表的相交 链表的相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
思路:也是比较简单的,感觉是个数学问题呀。注意点:比较的链表的地址,而不是里面的val值哦!
链表的长度相等的时候:定义两个指针分别指向a和b,指针不断的向前移动,每移动一次就比较两者的地址是否相等,而如果长度不相等的话:走的总长度是一样的:(都是9步)
对于a来说:4->1->8->4->5->null->5->0->1
对于b来说:5->0->1->8->4->5->null->4->1
代码如下:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
{
ListNode *a = headA;
ListNode *b = headB;
while(a!=b)
{
// a不为空的时候:一直向前移动
if(a!=nullptr)
a=a->next;
else
a=headB;
if(b!=nullptr)
b=b->next;
else
b=HeadA;
}
// 简洁一点的代码:
while(a!=b)
{
a!=nullptr?a=a->next:a=headB;
b!=nullptr?b=b->next:b=headA;
}
return a;
}
测试代码:
list.h
struct ListNode
{
int val;
ListNode* next;
//构造函数有3种形式
ListNode(int val) :val(val), next(nullptr){}
};
class MyLinkedList {
public:
//构造函数,构造空链表
MyLinkedList() {
//创建头结点
head = new ListNode(0);
_size = 0;
}
int get(int index);
void addAtHead(int val);
void addAtTail(int val);
void addAtIndex(int index, int val);
void deleteAtIndex(int index);
void showList();
private:
ListNode* head;
int _size;
};
list.cpp
int MyLinkedList::get(int index) {
if (_size<index + 1 || index<0)
return -1;
ListNode *cur = head;
for (int i = 0; i<index + 1; i++)
{
cur = cur->next;
}
return cur->val;
}
//先连接后面,再连接前面!顺序不能颠倒,否则将会找不到首元结点。
void MyLinkedList::addAtHead(int val) {
ListNode* newNode = new ListNode(val);
//首元结点和头结点断开,新节点和首元结点相连接。
newNode->next = head->next;
//头结点和新的结点相连接。
head->next = newNode;
_size++;
}
//结点的尾插`
void MyLinkedList::addAtTail(int val) {
ListNode* newNode = new ListNode(val);
//创建一个结点cur,指向头结点
ListNode* cur = head;
//说明:当前结点不是最后一个结点,一直向后寻找,直到cur->next为空,
//此时说明到达最后一个结点
while (cur->next != nullptr)
{
cur = cur->next;
}
//当前结点连接新的结点,_size+1;
cur->next = newNode;
_size++;
}
void MyLinkedList::showList()
{
ListNode *cur = head;
while (cur->next!=nullptr)
{
cur = cur->next;
cout << cur->val << " ";
}
cout << endl;
}
void MyLinkedList::addAtIndex(int index, int val) {
if (index <= 0)
addAtHead(val);
else if(index == _size)
addAtTail(val);
else
{
ListNode * cur = head;
ListNode *newNode = new ListNode(val);
//找到索引值的前一个位置
for (int i = 0; i < index; i++)
{
cur = cur->next;
}
//新节点的下一个结点就是索引处结点
newNode->next = cur->next;
//前一个结点的下一个结点是新节点
cur->next = newNode;
}
}
void MyLinkedList::deleteAtIndex(int index) {
ListNode* cur = head;
for (int i = 0; i < index; ++i)
{
cur = cur->next;
}
ListNode *tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
main.c
#include "list.h"
int main()
{
//因为4是一个常数,所以必须加上const
const int& a = 4;
MyLinkedList* list = new MyLinkedList();
list->addAtHead(1);
list->addAtTail(3);
list->addAtIndex(1, 2);
int i1=list->get(1);
cout << i1 << endl;
list->deleteAtIndex(1);
int i2 = list->get(1);
cout << "list[i]=" << i2 << endl;
return 0;
}