个人第一次思路: 其实我个人的第一个思路是比较暴力的,我第一遍暴力遍历链表,把链表的所有数值全部都保存到数组里面,然后翻转这个数组,再重复的覆盖当前的这个链表。但是这样子的实现方式实在是太暴力了,没有什么必要。
算法思路(双指针):
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
ListNode* pre = nullptr;
ListNode* cur = head;
ListNode* temp{};
while (cur != nullptr)
{
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
delete temp;
return pre;
}
};
递归法:
其实对于我个人来说,我感觉递归如果理解了还是很容易的,但是有时候如果不理解他的结束条件和初始化的设置的话,还是感觉一下子不能明白。这个题目的递归相对来说还是挺容易一下子就理解的,递归就是反复去执行相同的操作。
下面的代码还是可以更加的简洁的,比如传入的变量的设置。
class Solution {
public:
ListNode* reverse(ListNode* pre, ListNode* cur)
{
//递归就反复的执行同一个步骤
if (cur == nullptr) return pre;
ListNode* temp = cur->next;
cur->next = pre;
/* pre = cur;
cur = temp;*/
//递归其实就是做了上面这两步,可以自己画图去理解一下
return reverse(cur, temp);
}
ListNode* reverseList(ListNode* head)
{
ListNode* pre = nullptr;
ListNode* cur = head;
return reverse(pre, cur);
}
};
代码思路:使用虚拟头结点的方式去解决
一共分成了四步骤来走
class Solution
{
public:
ListNode* swapPairs(ListNode* head)
{
//使用虚拟头结点的方式
ListNode* dummyHead = new ListNode();
dummyHead->next = head;
ListNode* cur = dummyHead; //cur节点先指向虚拟头节点
//循环结束的终止条件
while (cur->next != nullptr && cur->next->next != nullptr)
{
//先保存我们之后要改变节点的指向,防止节点丢失
ListNode* temp = cur->next;
ListNode* temp2 = cur->next->next->next;
cur->next = cur->next->next; //步骤1
cur->next->next = temp; //步骤2
cur->next->next->next = temp2; //步骤3
//4. 移动cur指针
cur= cur->next->next;
}
return dummyHead->next;
}
};
我第一次想到的解决方案,其实感觉也还是很暴力啊,而且还不能通过
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int count = 0;
ListNode* cur = head;
while (cur->next!=NULL)
{
count++;
cur = cur->next;
}
int Index = count - n - 1;
while (Index--)
{
cur = cur->next;
}
ListNode* temp = cur->next;
cur->next = temp->next;
delete temp;
return head;
}
}
其实这个题目用双指针的话真的还是挺方便的,而且我感觉还挺很简单的啊,但是自己为什么最开始的就想起来要用双指针啊!!
这个代码写起来运行的时候还是有问题的:有两个特殊情况是我最开始没有考虑到的
我直接增加了对一个元素的判断,但是还是不可以通过,想到的问题就是
在这里如果使用虚拟头节点的方式来处理,真的就简单了,如果不用的话,要对很多特殊情况都做一个考虑说明,代码太复杂了,没必要这样子折磨我自己,啊哈哈哈哈
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if ( n == 0 || head == nullptr ) return head;
if(head->next == nullptr && n == 1) return nullptr;
ListNode* Slow = head;
ListNode* Fast = head;
while (n-- && Fast != nullptr)
{
Fast = Fast->next;
}
while (Fast->next != nullptr)
{
Fast = Fast->next;
Slow = Slow->next;
}
ListNode* temp = Slow->next;
Slow->next = Slow->next->next;
delete temp;
return head;
}
};
这一次终于通过了!!呜呜呜!!
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if ( n == 0 || head==nullptr ) return head;
ListNode* dummyHead = new ListNode();
dummyHead->next = head;
ListNode* Slow = dummyHead;
ListNode* Fast = dummyHead;
while (n--)
{
Fast = Fast->next;
}
while (Fast->next != nullptr)
{
Fast = Fast->next;
Slow = Slow->next;
}
Slow->next = Slow->next->next;
return dummyHead->next;
}
};
在这里其实要思考的问题就是如何同步,也是使用的是双指针的方式去解决
这是我第一遍自己写的题解,我不知道哪里有问题啊,能跑过18个案例了,我寻思这个也没什么特殊情况要考虑的吧?
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
if (headA == nullptr || headB == nullptr) return nullptr;
ListNode* PointA = headA;
ListNode* PointB = headB;
int countA = 0;
int countB = 0;
while (PointA != nullptr)
{
countA++;
PointA = PointA->next;
}
while (PointB != nullptr)
{
countB++;
PointB = PointB->next;
}
PointA = headA;
PointB = headB;
//减去差值,然后移动A或者B
int num = 0;
if (countA >= countB)
{
num = countA - countB;
while (num)
{
num--;
PointA = PointA->next;
}
while (PointA!=nullptr || PointB != PointA)
{
PointA = PointA->next;
PointB = PointB->next;
}
return PointA;
}
else
{
num = countB - countA;
while (num)
{
num--;
PointB = PointB->next;
}
while (PointA != nullptr || PointB != PointA)
{
PointA = PointA->next;
PointB = PointB->next;
}
return PointA;
}
return PointA;
}
};
稍微修改了一些细节,然后检查了一下就通过了
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
if (headA == nullptr || headB == nullptr) return nullptr;
ListNode* PointA = headA;
ListNode* PointB = headB;
int countA = 0;
int countB = 0;
while (PointA != nullptr)
{
countA++;
PointA = PointA->next;
}
while (PointB != nullptr)
{
countB++;
PointB = PointB->next;
}
PointA = headA;
PointB = headB;
//减去差值,然后移动A或者B
if (countA < countB)
{
//交换可以统一后面判断的标准
swap(countA, countB);
swap(PointA, PointB);
}
int num = countA - countB;
while (num--) PointA = PointA->next;
while (PointA != nullptr)
{
if (PointA == PointB) return PointA;
PointA = PointA->next;
PointB = PointB->next;
}
return nullptr;
}
};
原来的代码修改了一下逻辑,但是说实话一个swap交换下,可以减少后面这里的很多判断
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
if (headA == nullptr || headB == nullptr) return nullptr;
ListNode* PointA = headA;
ListNode* PointB = headB;
int countA = 0;
int countB = 0;
while (PointA != nullptr)
{
countA++;
PointA = PointA->next;
}
while (PointB != nullptr)
{
countB++;
PointB = PointB->next;
}
PointA = headA;
PointB = headB;
//减去差值,然后移动A或者B
if (countA < countB)
{
//交换可以统一后面判断的标准
swap(countA, countB);
swap(PointA, PointB);
}
int num = countA - countB;
while (num--) PointA = PointA->next;
while (PointA != nullptr)
{
if (PointA == PointB) return PointA;
PointA = PointA->next;
PointB = PointB->next;
}
return nullptr;
}
};
添加IP地址和端口控件
通过添加了两个控件,一个初始化的时候传入IP地址一个初始化的时候传入端口的地址。
修改InitSocket函数,传入IP地址和端口
程序在运行的时候出现了链接不上的问题,原因是在于网络传输的字节序是有问题的,在网络中传输字节序的时候要多注意
文件树控件和获取驱动信息功能
size_t len = recv(m_sock, buffer + index, BUFFER_SIZE - index, 0);
//服务端必须要发送xiao'xi
CServSocket::GetInstance()->Send(pack);
调试的时候发现这个len是0,表明客户端没有接收到来自服务端发送的消息信息
只是看了书,没有做笔记,明天再做把。。。。
了解了一下C++设计模式中的类图的内容,描述类与类之间的关系
最近在写的这个远程控制的项目就是采用的单例设计模式的思想
单例设计经常被使用到,是一种比较重要的设计模式,需要熟练的掌握
在应用系统开发中,我们常常有以下需求:
1.需要生成唯一序列的环境
2.需要频繁实例化然后销毁的对象。
3.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
4.方便资源相互通信的环境
实际案例:
class Single
{
public:
static Single* GetInstance()//2. 提供一个全局的静态方法,访问唯一的对象
{
if (m_single == nullptr)
{
m_single = new Single;
}
return m_single;
}
void Print()
{
std::cout << "This is Print Func" << char(10);
}
private:
static Single* m_single;//3. 类中定义一个静态的指针,指向唯一的对象
Single()
{
std::cout << "This is Single()" << char(10);
m_single = nullptr;
} //1. 构造函数私有化
};
Single* Single::m_single = nullptr; //初始化操作
int main()
{
//虽然构造函数是不可以被调用了的,但是可以声明指向这个类的指针
Single* P1 = Single::GetInstance();
Single* P2 = Single::GetInstance();
P1->Print();
P2->Print();
std::cout << hex << P1 << char(10);
std::cout << hex << P2 << char(10);
return 0;
}
饿汉式代码其实就是在类外静态指针初始化的时候直接去new申请了内存空间,这样我们在不需要再GetInstance中去判断初始化操作了
整体的效果和懒汉式是一样的,但是实现的思想是不同的。
饿汉式可能会出现多线程对资源争夺的问题,在日后的学习中心需要多多注意这方面的内容
class Single
{
public:
static Single* GetInstance()//2. 提供一个全局的静态方法,访问唯一的对象
{
//if (m_single == nullptr)
//{
// m_single = new Single;
//}
return m_single;
}
void Print()
{
std::cout << "This is Print Func" << char(10);
}
private:
static Single* m_single;//3. 类中定义一个静态的指针,指向唯一的对象
Single()
{
std::cout << "This is Single()" << char(10);
m_single = nullptr;
} //1. 构造函数私有化
};
Single* Single::m_single = new Single; //初始化操作
int main()
{
//虽然构造函数是不可以被调用了的,但是可以声明指向这个类的指针
Single* P1 = Single::GetInstance();
Single* P2 = Single::GetInstance();
P1->Print();
P2->Print();
std::cout << hex << P1 << char(10);
std::cout << hex << P2 << char(10);
return 0;
}