数组和指针

在Java中,只有一种方法可以创建数组:

int A[] = new int[100];

另一方面,c++提供了两种不同的方法来创建数组。

第一个方法是创建一个自动数组:

int [100];// A是一个包含100个整数的数组

这被称为自动数组,因为它被设计为当您离开创建它的作用域时自动消失。例如,如果将自动数组设置为函数或方法中的局部变量,那么一旦退出该函数,该数组就会自动消失。

第二种方法使用指针变量和new操作符的组合。

int *A = new int[100];// A指向一个包含100个整数的数组

无论您是使用方法1还是方法2创建数组,您都将以与在Java程序中相同的方式与数组进行交互。您可以使用数组索引表示法访问和处理数组中的单个单元格。

n++ = (n+1)*(n+1);//用一个正方形列表填充数组int total = 0;for(int n = 0;n < 100;n++) total += A[n];//把平方加起来

如果您使用上面的方法1创建了数组,那么当您退出创建它的作用域时,该数组将自动消失。如果你通过new操作创建了数组,你需要使用delete[]操作符显式地让数组消失:

删除();

作为使用传统数组索引表示法的替代方法,您还可以使用指针访问数组中的元素并与之交互。

这个过程首先复制一个指向数组的指针:

int *ptr = A;// PTR现在也指向数组的起始点。

该指针指向数组中的第一个元素。可以解引用该指针来访问数组元素。

*ptr = 12;// PTR指向数组中的第一个位置。//这将设置数组中的第一个位置为12。Int y = *ptr;//复制ptr所指向的值到y中

指向数组的指针变量也可以通过指针自增和自减操作在数组中移动。

ptr + +;// PTR现在指向数组中的第二个数据项PTR——;// PTR现在指向数组中的第一个数据项

指向数组的指针变量也可以通过指针算术来修改。

int *end = A + 100;// end指向A的起始点//后100个空格,即数组的末尾

最后,指针变量可以通过常用的==和!=比较操作符进行比较。下面是一些使用指针初始化数组内容的代码。注意,在循环中使用了!=比较操作符。

int *A = new int[100];int *ptr = A;int *end = A + 100;While (ptr != end) {*ptr = 0;ptr + +;}

排序任务

这些课堂笔记将带我们通过两个迭代的程序来完成一个简单的任务。我们将编写一个程序,它可以从文本文件中读取整数列表,用基本排序算法对这些整数进行排序,然后将排序后的列表写入第二个文本文件。在第一次迭代中,我们将使用传统的数组表示法编写程序。在第二次迭代中,我们将只使用指针完成相同的任务。

要使用ifstream从文本文件中读取整数列表,我们将使用以下代码。

std:: ifstream;//在.open("numbers.txt")中声明ifstream对象;//打开文件int x;while(in >> x){//从文件中读取一个数字//用x}做一些事情in.close();//关闭文件

如果使用的是Visual Studio,只要确保名为numbers.txt的文本文件与程序的源代码位于同一目录中,这段代码就可以正常工作。在Xcode中,你必须将open函数中的文件名替换为相关文件的完整路径。

这个例子用ifstream演示了“读取直到完成”的范例。>> x中的语句每次执行时都会从ifstream中读取一个int值。作为一个副作用,当文件中没有剩余的数字时,该语句将计算为0,这反过来导致我们在到达输入文件的末尾时退出while循环。

要将包含N个元素的int数组A的内容写入文本文件,我们使用以下代码。

std:: ofstream;//声明一个ofstream对象out.open("output.txt");//打开文件for(int n = 0;n < n;n++) out << A[n] << std::endl;//把数字写出来。close();//关闭文件

稍后我们将看到一个程序,它从文本文件中将整型数列表读入数组。读取后,我们将希望将数组中的数字按升序排序。这是一个基本排序算法的代码,插入排序。

void sort(int A[],int N) {for(int N = 1; N < N; N ++) {int mover = A[N];Int k = n;虽然(k > 0) {((k - 1) > mover) {[k] = (k - 1);k,;} else break;} A[k] = mover;}}

这个算法系统地遍历数组中的赢博体育元素,试图将每个元素放到正确的位置。主循环使用索引n来遍历元素。每次主循环迭代时,算法都会获取数组中位置n处的元素(称为mover),并尝试将其插入正确的位置。算法通过将移动项与数组中它之前的每个项进行比较来实现这一点。该算法使用索引为k的内部循环从位置n-1向下迭代到位置0。如果移动器小于位置k-1中的项目,我们将该项目向右移动一个空间以创建一个间隙。只要我们遇到一个小于或等于移动项的项,我们就会停止并将移动项放入我们创建的最后一个间隙中。

这里现在是源代码的第一个版本的数字排序程序。

#include <iostream> #include <fstream> //对数组进行插入排序void Sort (int A[],int N) {for(int N = 1; N < N; N ++) {int mover = A[N];Int k = n;虽然(k > 0) {((k - 1) > mover) {[k] = (k - 1);k,;} else break;} A[k] = mover;}} int main (int argc, const char * argv[]) {std::ifstream in;std:: ofstream;int N = 100;Int n = 0;int k;int* A = new int[N];in.open(“numbers.txt”);int x;while(in >> x){//根据需要调整A数组的大小。if(n == n) {int* B = new int[2* n];for(k = 0;k < n;k++) B[k] = A[k];删除();A = b;N *= 2;} A[n] = x;n + +;} in.close ();std::cout << “从文件中读取” << n << “整数。”< < std:: endl;排序(n);out.open(“sorted.txt”);for(k = 0;k < n;k++) out << A[k] << std::endl;out.close ();删除();std::cout << “已完成排序和保存。”< < std:: endl;返回0;}

这里还有一件特别的事情我们需要评论一下。因为我们不知道文本文件中会有多少个数字,我们必须先创建一个数组,然后在需要更多空间时调整它的大小。这个过程首先创建一个初始的100个整数数组:

int N = 100;int* A = new int[N];

在读取数字的循环中,我们放入以下代码:

//根据需要调整A数组的大小。if(n == n) {int* B = new int[2* n];for(k = 0;k < n;k++) B[k] = A[k];删除();A = b;N *= 2;}

这段代码以一个测试开始,该测试检查a数组是否刚刚耗尽空间。如果存在,则通过创建一个新的int数组来响应,该数组的空间可容纳两倍的数字。我们将A中的数字复制到这个新数组中,销毁A曾经指向的旧数组,最后使A指向我们创建的新数组。

从索引切换到指针

在第一个版本的排序程序中,我们已经在数组创建过程中有限地使用了指针。一旦创建了数组,我们就切换到更传统的数组索引表示法来处理数组。

标准指针操作使得我们可以用整型下标和标准括号表示法做任何事情。在这堂课稍晚的时候,我将把我们上面开发的排序程序完全转换成一个使用点作为赢博体育逻辑的程序。

在此之前,让我们先看一个简单的从数组表示法到指针表示法的转换示例。下面是一个函数,它执行线性搜索以确定给定项是否出现在数组中。

//返回x出现的第一个索引,如果它不出现在数组A中,则返回N。// int search(int A[],int N,int x) {int k = 0;while(k < N) {if(A[k] == x)返回k;其他k + +;}返回N;}

下面是用指针实现的同一个函数。

//返回指向x出现的第一个位置的指针,或者//如果x没有出现在//指针开始和结束的范围内,则返回结束。//这个函数假设开始点指向要搜索的第一项,结束点在最后一项后面。Int * search(Int *begin, Int *end, Int x) {Int * PTR = begin;While (ptr != end) {if(*ptr == x) return ptr;其他ptr + +;}返回end;}

这里是插入排序算法,重写为使用指针而不是传统的数组索引。

//对begin和end之间的项进行排序。// end应该指向正在排序的值范围的末尾。void sort(int *begin,int *end){//使用插入排序对数组进行排序int *mover = begin;//移动对象指向要插入的元素。发+ +;While (mover != end) {int value = *mover;//被插入项的值//当前指针将扫描数组中出现在移动位置之前的部分//Int *current = mover;While (current != begin) {// previous指向当前之前的位置int *previous = current;前,;//只要我们一直看到大于//要插入的值的数字,我们就会继续把东西移到一边,为我们想要插入的值腾出空间。如果(*先前的>值){*当前= *先前;当前,;} else break;} //将值放入合适的位置,并继续插入下一个//项。*current = value;发+ +;}}

理解这个函数的最佳方法是手工跟踪一个简单的示例。例如,如果我们使用这段代码对一个初始内容为{3,4,1,6,5,2}的数组进行排序,那么在排序过程的一部分,我们将得到如下所示的结果:

要使用这个函数,我们将使用如下代码:

排序(一+ n);

这段代码假设A是指向数组开头的指针。我们要排序的范围是从位置0开始到位置n之前结束的索引[0,n]的范围。

编程练习

下面是使用上面所示的指针插入排序函数对数字文件进行排序的程序的完整源代码。

构造一个使用不同排序算法的程序版本。下面是另一种排序算法的代码,称为选择排序。选择排序使用的策略是在数组的一部分中搜索它能找到的最小的数字。一旦它找到了最小的数字,它就会把它移动到范围的开始,让它与范围开始的数字交换位置。在排序过程的第一次迭代中,我们将搜索从索引0到索引N-1的整个数组,以查找其最小的数。在搜索过程的第二次迭代中,我们将搜索索引1和N-1之间的数组部分,以查找该范围内最小的数字,因为我们已经找到了最小的数字并将其放置在位置0。这个过程以这种方式继续进行,排序过程的第k次迭代在从k到N-1的索引范围内搜索列表中第k个最小的数字。

selectionSort()函数使用了一个辅助函数swap(),该函数使a中的两个项目交换位置。

//交换位置i和j中的项//数组A的void Swap (int A[],int i, int j) {int temp = A[i];A[i] = A[j];A[j] = temp;} void selectionSort(int A[],int N) {for(int k=0;k< N;k++) {int min = k;For (int n = k+1;n < n;n++){if (A[n] < A[min]) {min = n;}} swap(A,min,k);}}

构造一个使用指针代替整数下标和标准a [n]表示法的selectionSort版本。重写我上面链接到的程序,用这个排序算法代替原来的算法。