一、 数组


前言

我在leetcode上刷了一些算法和学习了c++语法后,经常对c++中的一些基础操作不太熟练,如链表的插入、删除、遍历二叉树等,这些操作对我来说应该熟记于心,滚瓜烂熟。


一、数组的定义及相关操作

1.数组是一块连续的内存,并按照顺序存储数据,创建数组时,需要先指定数组的容量大小,在根据大小分配内存,因为需要先进行内存的分配,所以数据的空间利用率不高,经常有空闲的区域。
2.数组可以看成是一个哈希表,其下标为Key,下表对应的数据为Value,可以使用时间复杂度O(1)进行查找
3.C++中的STL中的vector,就是一个动态数组,vector和普通数组的区别是,vector是动态分配内存的,每次扩充内存,是前一次的两倍

1.1 数组的声明

数组的声明需要指定数据类型和元素数量
类型 名称 [ 元素数量 ];
double balance [10];

1.2 数组的初始化

double balance[5] = {10.0, 5, 5.0, 2.0, 3.0}

1.3 vector——c++中的特殊数组(比数组好用的数组)

vector不光数组的大小是可以灵活设置的,还有很多相关的函数可以使用

vector的定义: vector<int> vector_name

size():返回向量中元素的个数。
push_back(value):将一个元素添加到向量的末尾。
pop_back():删除向量末尾的元素。
insert(position, value):在指定位置插入一个元素。
erase(position):删除指定位置的元素。
clear():删除向量中的所有元素。
empty():检查向量是否为空,返回一个布尔值。
front():返回向量中第一个元素的引用。
back():返回向量中最后一个元素的引用。
at(index):返回指定索引位置的元素的引用,带有边界检查。
resize(new_size):改变向量的大小,可以增加或减少元素的数量。
reserve(new_capacity):改变向量的容量,实际上并不改变向量的大小。
swap(other_vector):交换两个向量的内容。
begin() 和 end():返回指向向量首元素和尾后元素的迭代器。

1.3 题目1:返回数组中重复的数字(力扣442题)

题目描述:给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。

1.3.1 完成代码1——原地哈希

时间复杂度o(n),空间复杂度o(1)

#include<iostream>
#include<string>
#include <vector>
using namespace std;
vector <int> find_fuc(vector<int> &nums)
{
	int nums_len = nums.size();
	int n = nums_len;
	vector<int> ret;
	for (auto &num : nums)
	{
		int x = (num - 1) % nums_len;
		nums[x] += nums_len;
	}
	while (n-- > 0)
	{
		if (nums[n] > 2 * nums_len) ret.push_back(n);
	return ret;
}
void test1()
{
	//vector<int> nums = { 10,2,8,9,10,10,10,7,3,2,5 ,7};
	vector<int> nums = {};
	int nums_len = nums.size();
	vector<int> results = find_fuc(nums);
	cout << "重复的数据为:";
	for (const auto& result : results)
	{
		cout << (result+1) % nums_len << " ";
	}
}
int main()
{
	test1();
	return 0;
}
1.3.1.1代码中相关命令的学习
  1. auto:auto是关键字,可以自动推导数据类型,好处是简化代码,提高代码的可读性
    auto num = 10;
    auto name = “zzy”

  2. const auto& result : results
    这段代码中声明了result变量,该变量每次从results中引用一个值,使用 & 的目的是不对results进行拷贝,直接使用,可以节省空间。使用const关键字的目的是只能读取result的值,不能进行修改,保证代码的健壮性。

  3. for (const auto& result : results)
    这里的 for(int result:results),是一种范围基本循环,results可以是数组、向量、列表等容器,每次将容器中的内容传输到result。

  4. ret.push_back(n)
    每次向ret向量中的尾部传入一个值

1.3.2完成代码二——哈希表

时间复杂度o(n),空间复杂度o(n)
创建一个动态数组当作哈希表

#include<iostream>
#include<string>
#include <vector>
using namespace std;

vector <int> find_fuc(vector<int> &nums)
{
	int nums_len = nums.size();
	int n = 0;
	int* countings = new int[nums_len]();
	//int countings[nums_len] = {0};
	vector<int> ret;
	for (int &num : nums)
	{
		int x = num - 1;
		countings[x] += 1;
	}
	for(int i = 0; i < nums_len; i++)
	{
		n++;
		if (countings[i] >= 2) ret.push_back(n);
	//	cout << n <<":"<< nums[n]<< endl;
	}
	delete[] countings;
	return ret;
}


void test1()
{
//	vector<int> nums = { 10,2,8,9,10,10,10,7,3,2,5 ,7};
	vector<int> nums = {1,1,1,1,1,5,5,3,1,5,3,4,5,6,9,9};
	int nums_len = nums.size();
	vector<int> results = find_fuc(nums);
	cout << "重复的数据为:";
	for (const auto& result : results)
	{
		cout << result % nums_len << " ";
	}
}

int main()
{
	test1();
	return 0;
}
1.3.2.1代码内容学习

上述代码,我在运行时出现了一些问题

问题1:

定义数组时出错,报错原因时数组定义时,nums_len是一个变量导致的,而数组的空间大小,是需要在编译的时候就定义好的

相关代码:	int countings[nums_len] = {0};

解决方法,设置一个动态数组

动态数组的设置命令 int* countings = new int[nums_len]();

使用动态数组的时候要注意,使用完成后一定要手动释放空间,不然会造成内存泄漏

释放空间命令 delete[] countings;

在这里,出现的c++内存分配的情况,在大型项目中,需要合理的分配内存的使用情况,而堆(heap)时由开发人员手动进行分配和释放的,在使用时非常灵活,所以一些大型数据或对象中,经常使用堆的方式来创建

使用new在堆上创建对象的几种方式

创建单个对象:		MyClass* obj = new MyClass;
创建对象数组:		MyClass* objArray = new MyClass[5];
创建对象并初始化:	MyClass* obj = new MyClass(42);

使用delete释放内存的方式:

释放对象:	  delete obj;
释放对象数组: delete[] objArray;
问题2:

无法使用范围-based for 循环传递数据,也就是这种形式:for (const auto& counting : countings)
因为countings是针类型,不是数组、容器、列表、字符串的形式,所以不能用

1.4多维数组

多维数组的定义:type name[size1][size2][size3];
定义一个整型的二维数组:int threedim[2][2] = {{1,2},{4,5}}

1.4.1 题目:二维数组中的查找

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的个二维数组和一个整数,判断数组中是否含有该整数。

#include<iostream>
#include<string>
#include <vector>
using namespace std;
bool Find(int* matrix, int rows, int columns, int number)
{
	bool found = false;
    if (matrix != nullptr && rows > 0 && columns > 0)
    {
        int row = 0;
        int column = columns - 1;
        while (row < rows && column >= 0)
        {
            //cout << "matrix[row * columns + column]:" << matrix[] << endl;
            if (matrix[row * columns + column] == number)
            {
                found = true;
                break;
            }
            else if (matrix[row * columns + column] > number)
                --column;
            else
                ++row;
        }
    }
    return found;
}
void Test1()
{
	int matrix[][4] = { {1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15} };
	cout << Find((int*)matrix, 4, 4, 16) << endl;
}

int main()
{
	Test1();
	return 0;
}
1.4.1.1 代码中遇到的问题

1.如果输入的二维数组是空的,那么在判断的时候就需要设置空指针的判断

判断空指针:if (matrix != nullptr)

这里的nullptr常用于初始化空类型的指针

2.为什么Find函数中可以使用 if (matrix[row * columns + column] == number)来判断二位数组对应位置是否等于指定数,而在find函数外部,matix[nums]输出的却是地址?

这是因为Find(int* matrix, int rows, int columns, int number)输入的二维数组的指针,也就是首地址,所以在Find函数内部输出martix[num]输出的是int类型的值,而Find函数外部,使用martix[num]输出的是二维数组中的num行的首地址。

Leetcode题目:长度最小的子数组

这道题用滑动窗口解决,但是跟我理解的滑动窗口是有区别的,滑动窗口随时可变,很巧妙
https://assets.leetcode-cn.com/solution-static/209/1.png
这个是图片的链接,可以看看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值