数组及常用算法

215 阅读6分钟

数组

数组是可以在内存中连续存储多个元素的结构,数组是一个类型例如 int [], double [] ,数组中所有元素必须属于相同的数据类型。在内存中的存放方式为:

变量:内存中的一块空间
数组:内存中的一串连续的空间

数组必须先声明,再使用,数组的长度固定不变,避免数组越界。必须在定义数组的时候明确数组的长度

定义数组

dataType arrayName[size];
dataType arrayName[] = {elements, ...}
dataType arrayName[]{elements, ...}

定义数组有以下几个注意点:

  1. size 可以只可以是常量(const int N,或者数字)。
  2. = 号可以省略,例如 int days[]{1, 15};
  3. 大括号内可为空,这样所有元素置零,例如 float m[100]{};
  4. 但是大括号内和 size 不能同时为空,必须要有一个标示数组大小的声明。

数组的初始化

int nums[5];  

这种声明数组中的内容是没有被初始化的,打印的话会显示数组分配的内存地址之前存储的内容。

int nums[5]{};  
int nums[5] = {1, 2}  
int nums[5] = {0}  

这几种声明则会将数组中的内容全部初始化为0。

#include <iostream>

using namespace std;

int main() {
    int nums_uninit[5];
    int nums_init1[5]{};
    int nums_init2[5]{1, 2};

    cout << "未初始化\t已初始化\t已初始化" << endl;
    for (int i = 0; i < 5; i++) {
        cout << nums_uninit[i] << "\t\t"
             << nums_init1[i] << "\t\t"
             << nums_init2[i] << endl;
    }

    return 0;
}
未初始化        已初始化1       已初始化2
8               0               1
0               0               2
0               0               0
0               0               0
4200112         0               0

从上面代码可以清晰看到,初始化过的数组和未初始化过的数组的区别。
为什么未初始化的数组会出现这种数字呢?下面是我在网上搜到的详细解释:

C语言的未初始化的数组的值为什么是随机的

数组的一些常用算法

动态的获取一个数组的大小:

sizeof(arrayName) / sizeof(dataType) ; 

上面这种方法只对于基础类型的数组有效。
另外一种获取方法:

sizeof(nums[0]);

这种方法不建议对未初始化的数组使用,因为数组位初始化,数据是随机的。采用上文说过的 int nums[5]{}; 的声明的话就可以使用,因为数组已经被初始化为0了。

以及字符串类型不能有上面这两种方法来获取,因为字符串的大小不是固定的,不能保证每个字符串的大小一致。

冒泡排序

算法步骤:

  1. 从第一个元素开始,比较和下一个元素的大小,若大于下一个元素则交换位置。
  2. 重复步骤 1 直到与最后一个元素比较完成。
  3. 这样就讲数组中最大的元素移动到了最后一个位置,标记为排序完成。
  4. 对剩余未排序完成的元素重复步骤 1 - 3 ,直至所有元素排序完成。
    // 冒泡排序(升序)
    int temp;
    for (int i = 0; i < nums_len - 1; i++) {        // 步骤 4
        // j++ 为步骤 2 ,j < nums_len -i - 1 为步骤 3
        for (int j = 0; j < nums_len - i - 1; j++) {
            if (nums[j] > nums[j+1]) {      // 步骤 1
                temp = nums[j];
                nums[j] = nums[j+1];
                nums[j+1] = temp;
            }
        }
    }

选择排序

算法步骤:

  1. 设定第一个未排序元素为最大值。
  2. 将最大值与剩下所有元素比较,找出未排序元素中的最大值。
  3. 若最大值不为第一个未排序元素,则与其交换位置。并标记第一个元素为排序完成。
  4. 重复步骤 1 - 3 直至所有元素排序完成。
    // 选择排序(降序)
    int temp;
    for (int i = 0; i < nums_len - 1; i++) {        //步骤 4
        int max = nums[i];      // 步骤 1
        int max_i = i;
        for (int j = i + 1; j < nums_len; j++) {    //步骤 2
            if (max < nums[j]) {
                max = nums[j];
                max_i = j;
            }
        }
        if (max_i != i) {       // 步骤 3
            temp = nums[i];
            nums[i] = nums[max_i];
            nums[max_i] = temp;
        }
    }

查找元素

    // 查找输入数字在数组中的下表,没找到则返回-1
    int target_index = -1;
    int target;
    cout << "请输入你要查找的数:";
    cin >> target;
    for (int i = 0; i < nums_len; i++) {
        if (nums[i] == target) {
            target_index = i;
            cout << "数字 " << target << " 在数组中的下标为:" << target_index
    << endl; break;
        }
    }
    if (target_index == -1)
        cout << "抱歉数字 " << target << " 没有在数组中找到。" << endl;
        

向量 vector

向量容器 vector 是一个快速的动态分配内层的数组。 有点像是C++中数组的升级版本,和python中的 list 类很相似。
动态数组,可以在运行阶段设置长度,有数组的快速索引方式,可以插入和删除元素。

定义和初始化

vector 的使用一定要导入 vector 头文件。它的定义和初始化有许多方法:

#include <vector>
vector<double> vec1;        //声明一个int型向量vec1
vector<string> vec2(5);     //声明一个初始大小为5的string型向量vec2
vector<int> vec3(20, 998);   //声明一个初始大小为20的int型向量vec3,并且所有初始值为998
vector<int> vec4(vec3);     //声明一个int型向量vec4,并用vec3初始化
vector<int> vec5(vec3.begin(), vec3.begin()+2);    //声明一个int型变量vec5,并用vec3
vector<int> vec6 {1, 2};    //声明一个int型变量vec6,并初始化为{1, 2}
//使用数组进行初始化
int nums[] {1, 2, 3};
vector<int> vec7(arr, arr+2);   //声明一个int型向量vec7,使用数组arr的0-2(3个元素)进行初始化
vector<int> vec8(&arr[1], &arr[2]);     //声明一个int型向量vec8,使用数组arr的1-2(两个元素)进行初始化

常用操作

方法名 用处
clear() 移除容器中的所有数据
empty() 判断容器是否为空
size() 返回容器中元素的个数
[index]、at(index) 返回索引为index的元素
erase(pos) 删除pos位置处的数据
erase(beg, end) 删除[beg, end]区间的数据
front() 返回第一个元素
insert(pos, elem) 在pos位置处插入一个元素
pop_back() 删除最后一个元素
push_back(elem) 在容器末尾插入一个元素
resize(num) 重新设置容器大小
begin()、end() 返回容器首位元素的迭代器

vector 扩容的基本步骤

  1. 创造一个新的连续内存空间
  2. 将原来内存空间中的数据拷贝到新的内存空间中
  3. 销毁原来内存空间中的数据

这里推荐 vector 里面存放指针,不要存放一些复杂类型的数据,因为其实它的效率没有普通数组高。

参考资料

C++ 复合类型之vector和array模板