利用动态规划算法解01背包问题->二维数组传参->cpp内存管理->堆和栈的区别->常见的内存错误及其对策->指针和数组的区别->32位系统是4G

简介: 1、利用动态规划算法解01背包问题https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html两层for循环,依次考察当前石块是否能放入背包。

1、利用动态规划算法解01背包问题

https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html

两层for循环,依次考察当前石块是否能放入背包。如果能,则考察放入该石块是否会得到当前背包尺寸的最优解。

// 01 knapsack problem dynamic programming algorithm

#include "pch.h"
#include <iostream>

void dynamic_program( int stone_num, int knapsack_capacity, int stone_weight[],  
	int stone_value [], int stone_in_or_not [], int (*V)[8]) {

	//栈内存需要初始化
	memset(V, 0, sizeof(V));

	for (int i = 0; i < stone_num; i++) {
		for (int j = 1; j <= knapsack_capacity; j++) {
			//此时背包无法装入当前石块
			if (j < stone_weight[i]) {
				V[i][j] = V[i - 1][j];
			}
			else {
				//不装入价值更大
				if (V[i - 1][j] > (V[i - 1][j - stone_weight[i]] + stone_value[i])) {
					V[i][j] = V[i - 1][j];
				}
				else {
					//前i-1个物品的最优解与第i个物品的价值之和最大
					V[i ][j] = (V[i - 1][j - stone_weight[i]] + stone_value[i]);
					stone_in_or_not[i] = 1;
				}
			}
		}
	}
	int a = 0;
}
void init() {
	int stone_num = 4, knapsack_capacity = 8;
	int stone_weight[] = { 2, 3, 4, 5 };
	int stone_value[] = { 3, 4, 5, 6 };
	int stone_in_or_not[] = { 0,0,0,0,0,0,0,0 };
	int V[4][8];
	dynamic_program(stone_num, knapsack_capacity, stone_weight, stone_value, stone_in_or_not, V);

}
int main()
{
    init();
	return 0;
}

 

2、二维数组传参

https://blog.csdn.net/yunyun1886358/article/details/5659851

int main()
{
    int m = 10;
    int n = 10;
    int** p = new int[m][n];
}

会发现编译不通过,第二个维度长度必须为常量。那么怎么声明一个两个维度都能动态指定的二维数组呢?看下面:

void func5(int** pArray, int m, int n)
{

}

#include <ctime>
int main()
{
    int m = 10;
    int n = 10;

    int** pArray = new int* [m];
    pArray[0] = new int[m * n]; // 分配连续内存

    // 用pArray[1][0]无法寻址,还需指定下标寻址方式
    for(int i = 1; i < m; i++)
    {
        pArray[i] = pArray[i-1] + n;
    }

    func5(pArray, m, n);
}

这里为二维数组申请了一段连续的内存,然后给每一个元素指定寻址方式(也可以为每一个元素分别申请内存,就不必指定寻址方式了),最后将双重指针作为实参传递给func5。这里func5多了两个形参,是二维数组的维度

 

3、堆和栈的区别

主要区别有以下几点

(1)管理方式不同(2)空间大小不同(3)能否产生碎片不同(4)生长方式不同

(5)分配方式不同(6)分配效率不同

 

4、常见的内存错误及其对策

(1)内存分配未成功,却使用了它。因为内存分配会不成功。

常用解决办法是,在使用内存之前检查指针是否为NULL。

如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。

如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。

(2)内存分配虽然成功,但是尚未初始化就引用它。

内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。

(3)内存分配成功并且已经初始化,但操作越过了内存的边界。

例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。

(4)忘记了释放内存,造成内存泄露。

含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。

(5)释放了内存却继续使用它。发生该情况有三种可能:

1). 程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。

2). 函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。

3). 使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。

那么如何避免产生野指针呢?这里列出了5条规则,平常写程序时多注意一下,养成良好的习惯。

规则1:用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。

规则2:不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。

规则3:避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。

规则4:动态内存的申请与释放必须配对,防止内存泄漏。

规则5:用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

 

5、指针和数组的区别

下面示例中,字符数组a的容量是6个字符,其内容为 hello。a的内容可以改变,如a[0]= ‘X’。指针p指向常量字符串“world”(位于静态存储区,内容为world),常量字符串的内容是不可以被修改的。从语法上看,编译器并不觉得语句p[0]= ‘X’有什么不妥,但是该语句企图修改常量字符串的内容而导致运行错误。

 

6、32位系统是4G

https://blog.csdn.net/nvd11/article/details/8749375

 

7、各种getmemory

https://blog.csdn.net/u010027547/article/details/52292889

 

参考文献:

assert()函数 :  https://www.cnblogs.com/lvchaoshun/p/7816288.html

cpp内存管理:  https://chenqx.github.io/2014/09/25/Cpp-Memory-Management/

二维数组传参:  https://blog.csdn.net/yunyun1886358/article/details/5659851

动态规划算法解决01背包问题: https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html

相关文章
|
缓存 监控 Linux
CentOS系统如何查看当前内存容量。
以上方法都不需要特殊软件或者复杂配置即可执行,在CentOS或其他Linux发行版中都适合运行,并且它们各自透露出不同角度对待问题解答方式:从简单快速到深入详尽;从用户态到核心态;从操作层数到硬件层数;满足不同用户需求与偏好。
940 8
|
存储 缓存 监控
手动清除Ubuntu系统中的内存缓存的步骤
此外,只有系统管理员或具有适当权限的用户才能执行这些命令,因为这涉及到系统级的操作。普通用户尝试执行这些操作会因权限不足而失败。
2362 22
|
监控 Linux Python
Linux系统资源管理:多角度查看内存使用情况。
要知道,透过内存管理的窗口,我们可以洞察到Linux系统运行的真实身姿,如同解剖学家透过微观镜,洞察生命的奥秘。记住,不要惧怕那些高深的命令和参数,他们只是你掌握系统"魔法棒"的钥匙,熟练掌握后,你就可以骄傲地说:Linux,我来了!
585 27
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
1354 38
【算法】栈
栈相关算法题,供参考,附有链接地址及板书
295 14
|
机器学习/深度学习 人工智能 缓存
【AI系统】推理内存布局
本文介绍了CPU和GPU的基础内存知识,NCHWX内存排布格式,以及MNN推理引擎如何通过数据内存重新排布进行内核优化,特别是针对WinoGrad卷积计算的优化方法,通过NC4HW4数据格式重排,有效利用了SIMD指令集特性,减少了cache miss,提高了计算效率。
858 3
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
机器学习/深度学习 人工智能 算法
【AI系统】内存分配算法
本文探讨了AI编译器前端优化中的内存分配问题,涵盖模型与硬件内存的发展、内存划分及其优化算法。文章首先分析了神经网络模型对NPU内存需求的增长趋势,随后详细介绍了静态与动态内存的概念及其实现方式,最后重点讨论了几种节省内存的算法,如空间换内存、计算换内存、模型压缩和内存复用等,旨在提高内存使用效率,减少碎片化,提升模型训练和推理的性能。
1020 1
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。

热门文章

最新文章