每日博客Day8

每日博客Day 8

每日算法

206.翻转链表

个人第一次思路: 其实我个人的第一个思路是比较暴力的,我第一遍暴力遍历链表,把链表的所有数值全部都保存到数组里面,然后翻转这个数组,再重复的覆盖当前的这个链表。但是这样子的实现方式实在是太暴力了,没有什么必要。

算法思路(双指针):

  1. 定义cur指针指向头结点,定义pre指针指向null(定义节点)
  2. 开始移动:先保存cur->next的节点为temp,不然后面不会丢失
  3. 往后面移动pre和cur指针,如果cur为NULL了,说明到了最后的位置,返回pre节点
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);
    }
};

24. 两两交换链表中的节点

代码思路:使用虚拟头结点的方式去解决

一共分成了四步骤来走

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;
	}
};

删除链表倒数的第N个节点

我第一次想到的解决方案,其实感觉也还是很暴力啊,而且还不能通过

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;
	}
}
双指针解法

其实这个题目用双指针的话真的还是挺方便的,而且我感觉还挺很简单的啊,但是自己为什么最开始的就想起来要用双指针啊!!

这个代码写起来运行的时候还是有问题的:有两个特殊情况是我最开始没有考虑到的

  1. 如果要删除的链表中只有一个元素怎么处理?

我直接增加了对一个元素的判断,但是还是不可以通过,想到的问题就是

  1. 如果要删除的元素是链表的头节点,该怎么处理?

在这里如果使用虚拟头节点的方式来处理,真的就简单了,如果不用的话,要对很多特殊情况都做一个考虑说明,代码太复杂了,没必要这样子折磨我自己,啊哈哈哈哈

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;
	}
};
19 双指针和虚拟头节点做法

这一次终于通过了!!呜呜呜!!

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;
	}
};

面试题 02.07. 链表相交

在这里其实要思考的问题就是如何同步,也是使用的是双指针的方式去解决

双指针解法

这是我第一遍自己写的题解,我不知道哪里有问题啊,能跑过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.方便资源相互通信的环境

实际案例:

  • 多线程中网络资源初始化
  • 回收站机制
  • 任务管理器
  • 应用程序日志管理

单列设计模式的实现步骤

  1. 构造函数私有化
  2. 提供一个全局的静态方法,访问唯一对象
  3. 类中定义一个静态指针,指向唯一对象

懒汉式代码

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值