前言:
此时兄弟们对“数组下标能为负数吗”大体比较关心,看官们都需要知道一些“数组下标能为负数吗”的相关内容。那么小编同时在网络上汇集了一些对于“数组下标能为负数吗””的相关内容,希望咱们能喜欢,咱们一起来了解一下吧!第一种最常用的就是
## 1.选择排序:
时间复杂度:O(N*N)
大致思想为:从第一个数开始,依次从后面所有数中挑出最小的那个数(包括比较第一个数),然后与第一个数进行数值交换。
自己写代码总会出现或多或少的小问题:
注意:
(1)swap函数记得加上头文件#include<algorithm>
(2)自己写交换函数记的用引用传递,int temp = a;a=b;
b=temp;这个交换顺序自己在纸上写一写。
(3)为了可以容纳多种类型数组,加入模板T,同时包装成一个函数,这样float型数组(小数),string型数组(字符串)都可以进行排序。
```cpp
#include<iostream>
using namespace std;
#include<algorithm>
//void swap(int& a, int& b)
//{
// int temp = a;
// a=b;
// b=temp;
//}
template<typename T>
void selectSort(T arr[], int n){
for(int i=0; i<n; i++)
{
int min = i;
for(int j=i+1; j<n; j++)
{
if(arr[j]<arr[min])
min = j;
}
swap(arr[i],arr[min]);
}
}
int main(){
int n=6;
int arr[6]={5,2,4,3,6,1};
selectSort(arr,6);
for(int k=0; k<n; k++)
{
//cout<<"排序后:"<<endl;
cout<<arr[k]<<" ";
}
while(1);
return 0;
}
```
后来专门搞了一个随机生成数组值得函数,放在SorttestHelper.h文件里,代码如下。
**这里学习到的一个点是它的返回类型是namespace,根据这个代码可知,该返回类型是一个指向新开辟的数组空间的指针。,但事实上它返回的数组空间,只是用指针表示一下。为什么这么说呢,int * arr = 该函数, 也就是用一个指针指向该函数返回的数组空间!注意在最后用delete[] arr; 释放一下那个函数开辟的数组空间。**
```cpp
#include<iostream>
#include<ctime>
#include<cassert>
using namespace std;
namespace SortTestHelper {
// 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
int *generateRandomArray(int n, int range_l, int range_r) {
int *arr = new int[n];
srand(time(NULL));
for (int i = 0; i < n; i++)
arr[i] = rand() % (range_r - range_l + 1) + range_l;
return arr;
}
```
## 2.插入排序:
时间复杂度:O(N*N)
选择排序的思想是从该数后面找到最小与该数进行交换,而插入排序的思想是,从第二个开始,把该数放到前面所有数的数组中对应的位置。(**一个是把后面整体看成数组,一个是把前面整体看成一个数组)**
```cpp
template<typename T>
void InsertSort(T arr[], int n){
for(int i =1; i<n; i++){
for(int j=i;j>0; j--){
if(arr[j]<arr[j-1])//!这里是关键,j和j-1比较!
swap(arr[j],arr[j-1]);
else
break;
}
}
}
```
再补充一个比较:这个插入排序是j和j-1进行比较,而选择排序是j和保存的最小值进行比较!
注意:**插入排序如果第一轮该数比前面的数组的第一个比较的数大,那么后面就不用再继续了。所以相对选择排序来说应该是更快一点!但是事实上,是可能快也可能慢,因为有时候插入排序相比选择排序需要交换更多次!所以下面出现了插入排序的优化!**
**但是插入排序最大的优点在于,对于接近有序的序列,插入排序可以实现效率非常的高,甚至比很多时间复杂度小的排序方法都高,而现实生活中很多事物的排序都属于接近有序的排序,比如不小心被打乱的时间,或者注册表等!所以其实用价值很高!可以降到o(n)的复杂度。**
## 插入排序优化:
观察下面的程序,改进后的方法:就是减少交换,把交换都换成了赋值。怎么个赋值法?
**把当前的数保存在一个临时变量中(对应T e = arr[i];),然后将前面的数组和临时变量比,要是临时变量小(或者说该数小),暂时先不和之前一样让他们交换,而是就把较大的数赋值给后面的小数,一直到前面数组中哪个数比该数小,好,跳出来,把该数放在数组中这个数后面!**
```cpp
template<typename T>
void InsertSort(T arr[], int n){
for(int i =1; i<n; i++){
T e = arr[i];
int j;
for( j=i;j>0 && e <arr[j-1]; j--){
arr[j]=arr[j-1];
}
arr[j] = e;
}
}
```
**最后再强调一下:**
**插入排序最大的优点在于,对于接近有序的序列,插入排序可以实现效率非常的高,甚至比很多时间复杂度小的排序方法都高,而现实生活中很多事物的排序都属于接近有序的排序,比如不小心被打乱的时间,或者注册表等!所以其实用价值很高!**
## 3.希尔排序(难)
时间复杂度:O(n^(1.3—2))
自我感觉写入排序的原理很好理解,就是把序列分组之后再进行插入排序,没有看过的可以看看这篇[希尔排序]()
难就难在代码的分析上:
下面是相对插入排序几个改动的地方,我依次解释:
```cpp
template<typename T>
void Shell_sort(T arr[], int n){
for(int gap = n/2; gap>0; gap/=2)//改动
{
//改动i=gap
for(int i =gap; i<n; i++){
T e = arr[i];
int j;
//改动j>gap,j<gap时就结束
//改动e <arr[j-gap]
//改动j-=gap
//改动j-=gap
for( j=i;j-gap>=0 && e <arr[j-gap]; j-=gap){
arr[j]=arr[j-gap];
}
arr[j] = e;
}
}
}
```
第一个改动就是加入了gap循环,这个gap既代表有几个分组,又代表分组后每个元素之间的间隔。它循环起来是因为希尔排序要进行多次分组,每次分组都不同。直到gap=0就不用分了,这时候就排好了。
第二次改动把插入排序的初始值换了,以前是从第2个数开始作为要插入的对象,往前面的数组插入,现在是先把第gap个数作为插入对象,**这个gap在它现在的分组中其实就是第2个数!**
第三个改动j-gap>=0,它就相当于之前插入排序的j-1>=0,这个不用理解,只要知道数组下标不能为负数,所以j-1≥0,所以j-gap>=0。
另外两个比较简单就不说了就不用说了。
注意:**分组之后的排序是交错排序,不是先把其中一组排完再排另一组!!!是按照顺序交错排序!**
## 4.冒泡排序
时间复杂度:O(N*N)
这个比较简单,就从第一个开始,与它相邻的比较,要是偏大就交换,这样一直交换下去,最后面的那个就得到了最大值。第一轮交换最后面那个值排好,第二轮倒数后两个值排好,既然每次倒着数都增加一个排好的值,那就每一轮减少一个值的排序,只用排序前n-i个。
```cpp
template<typename T>
void maopao_sort(T arr[], int n){
for(int i=0;i<n-1;i++){
for(int j=0;j<n-1-i; j++){
if(arr[j]>arr[j+1])
swap(arr[j],arr[j+1]);
}
}
}
```
**当然,其实你for(int j=0;j<n-1-i; j++)这里不需要-i也是可以的。每一轮把一个数冒到最后面去,需要n-1轮就把全部都冒到后面去了!所以叫冒泡排序!**
## 5.归并排序(中等难度)
归并排序就稍微麻烦一点,但是它的时间复杂度是nlogn,通过增大空间复杂度减少了时间复杂度,所以也应用广泛。
它的基本原理就是利用递归,先对数组二分法进行分组,分组之后对各个小组分别进行归并排序,然后分好的各个小组再分组,再各自进行归并排序,最后对整体进行一次归并排序。
它的代码如下,分为三个部分,第一部分换个名字,第二部分实现递归,第三部分实现最后的合并。其中第三部分最为复杂。
```cpp
//归并排序
template<typename T>
void merge(T arr[], int n){
//先给函数换个参数传递
_merge_sort(arr, 0, n-1);
}
template<typename T>
void _merge_sort(T arr[], int L,int R){
//利用递归方法,先找结束条件
if(L>=R)return;
//先把数组分成两份
int mid = (L+R)/2;//R-L
//再分别对分成的两组进行归并排序
_merge_sort(arr, L, mid);
_merge_sort(arr,mid+1,R);
//最后对整体进行归并排序
_merge(arr, L,mid,R);
}
template<typename T>
void _merge(T arr[],int L,int mid,int R){
T* aux = new T [R-L+1];//建立临时数组
//T aux[R-L+1];
//把原数组的值赋值到临时数组
//并且新数组的下标是从0开始的
for(int i= L; i<=R; i++){
aux[i-L] = arr[i];
}
//下面就是归并排序的核心思想了
int i =L;
int j =mid+1;
for(int k=L;k<=R;k++){
//是i>mid,不是>j
//前两个if是一端遍历完了,一端还没有
//后面两个是在借用临时数组把最小的按顺序保存到原数组中
//记得所有的aux里都要减去L
if(i>mid){
arr[k]=aux[j-L];
j++;//!不要忘记!
}else if(j>R)
{
arr[k]=aux[i-L];
i++;//!!
//下面这里注意,下面两个不能单独if出来,必须和上面一起
//因为当一端越界的时候,不能再执行下面的if判断,i越界还好,j越界就超出数组范围了
}else if(aux[i-L]<aux[j-L]){
arr[k]=aux[i-L];
i++;
}else{
arr[k]=aux[j-L];
j++;
}
}
delete[] aux;
}
```
## 对归并排序的优化
把第二个函数修改一下,改了两个地方:
第一个大于的时候在合并,不大于就不用了。
1.if(arr[mid]>arr[mid+1])//不大于的时候其实已经排好了
_merge(arr, L,mid,R);
2.改变结束条件,数组比较小的时候用插入排序就好!
```cpp
template<typename T>
void _merge_sort(T arr[], int L,int R){
//利用递归方法,先找结束条件
//if(L>=R)return;
if(R-L<=15){
InsertSort_merge(arr,L,R);
return;
}
//先把数组分成两份
int mid = (L+R)/2;//R-L
//再分别对分成的两组进行归并排序
_merge_sort(arr, L, mid);
_merge_sort(arr,mid+1,R);
//最后对整体进行归并排序
if(arr[mid]>arr[mid+1])//不大于的时候其实已经排好了
_merge(arr, L,mid,R);
}
```
## 自底向上的归并排序(难)
(这个比较难懂,初学者看不懂就放弃吧)
1.划分小段,划到最小,对各个小段分别进行归并排序
2.划分小段(相比上面的小段,各个小段更长),分别进行归并排序
3.一直到最后,对整个数组进行归并排序
整个过程不需要递归,只需要迭代就可以
```cpp
//自底向上的归并排序
template<typename T>
void mergeBU(T arr[], int n){
//第一层遍历是每次分组后的单组的元素个数
for(int sz=1; sz<=n; sz+=sz){
//每两个组进行一次归并排序处理
//i+sz<n保证了第二组的存在
//min()函数是为了不存在第二部分末尾的时候,就把末尾换成数组末尾
for(int i=0; i+sz<n;i+=sz+sz){
_merge(arr,i,i+sz-1,min(i+sz+sz-1,n-1));
}
}
}
```
优点:这种排序没有使用数组的一个特性,就是通过数组下标直接获得元素,时间复杂度是nlogn的时间,因此,可以非常好的对链表进行排序。
## 6.快速排序(最伟大的排序!)
快速排序的核心思想这个帖子讲的非常好:[快速排序]()
这里有句话
> 首先哨兵j开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵j先出动,这一点非常重要(请自己想一想为什么)
**搞清楚了,首先搞清一个原则,最后与基准数的交换,一定是与一个小于基准数的数交换!但是链接错误的地方在于,它的结束条件是两边指针汇合处,但汇合处可能大于0,也可能小于0,所以结束条件必须是左边指针大于右边指针,然后最后交换只能是和j交换,因为j暂停的时候指向是小于基准数的数,i大于j的时候,j指向也一定是小于基准数的数,这样最后交换才会成立。所以不论哪个指针先动都可以,只要改变结束条件就行!后面有我参考修正后的代码!**
上面是双路指针的快速排序,我先贴出快速排序的最原始的版本:
它的原理比较复杂,用的也不多,这里就不展开讲解,大致说下:
如下图,两个指针j,i; i进行遍历,当遇到小于基准数的值时,把它和j+1进行交换,即大于基准数组部分的第一个;当遇到大于基准数组的值时,不用动。最后把基准数和j(也就是小于基准数组部分的最后一个数)进行交换即可。
![在这里插入图片描述]()
```cpp
//快速排序原始形态
template<typename T>
void quick_sort(T arr[], int n){
//先换个名字
__quicksort(arr,0,n-1);
}
template<typename T>
void __quicksort(T arr[],int L,int R){
//结束条件
//if(L>=R)return;
//优化方案
if(R-L<=15){
InsertSort_merge(arr,L,R);
return;
}
//接下来找到中间值
int p = __patition(arr,L,R);
//对两边分别再用快速排序
__quicksort(arr,L,p);
__quicksort(arr,p+1,R);
}
template<typename T>
int __patition(T arr[], int L, int R){
//优化方案
srand((unsigned int)time(NULL));
swap(arr[L],arr[rand()%(R-L+1)+L]);
//创建一个临时基准数
T v = arr[L];
//arr[L+1,....j]<v ; arr[j+1....i]>v
int j=L;
for(int i=L+1;i<=R;i++){
if(arr[i]<v){
swap(arr[i],arr[j+1]);
j++;
}
}
swap(arr[L],arr[j]);
return j;
}
```
**原始快速排序的最大缺点是:针对特别有序的数组,排序起来可能特别慢!为什么呢?快速排序每次都是分为两部分,一边大于基准数,一边小于基准数,然后再对两边分别进行递归,但是当遇到几乎完全有序的数组时,分出来的就是,一边全是大于基准数的,一边什么都没有,这时候就要对另一边几乎剩余全部进行递归,依次下去,时间复杂度就退化回了O(n*n)了。这种情况的改进方法就是基准数不要从头开始,每次都随机选择一个!(优化方法如上!)**
**另外,针对重复数量比较多的数组,原始快速排序也会特别慢!上面原始排序如果遇到等于基准数是不动的,直接包含到大于基准数部分。跟上面的情况类似,如果全部都是等于基准数的值,那么几乎所有的数都被分到大于等于基准数那一部分,造成两部分严重失衡,最后退回到O(n*n)时间复杂度。针对这种情况,下面改进后 的双路快速排序改进了这种缺点。**
## 双路快速排序法(简单)
这种双路快速排序就是上面链接里的方法。**和原始快速排序相比,这次把大于小于基准数的部分放到了两边,i在中间移动。当两边指针都卡在等于v的元素上,就让他们交换位置。所以等于v的元素最终保留在两部分内,相比上面只保留在一部分要好很多!**
![在这里插入图片描述]()
![在这里插入图片描述]()
```cpp
template<typename T>
int __patition2(T arr[], int L, int R){
srand((unsigned int)time(NULL));
swap(arr[L],arr[rand()%(R-L+1)+L]);
//创建一个临时基准数
T v = arr[L];
//arr[L+1,....j]<v ; arr[j+1....i]>v
int i=L+1,j=R;
while(true){
//这里必须是i先循环,否则就会程序崩溃!!
//循环结束就停在了左侧第一个大于基准数的地方
while(arr[i]<v && i<=R)i++;
//循环结束## 标题就停在了右侧第一个小于基准数的地方
//!j>=L+1,否则程序崩溃!
while(arr[j]>v && j>=L+1)j--;
//如果指针重合并越界了
if(i>j)break;
swap(arr[i],arr[j]);
i++;
j--;
}
swap(arr[L],arr[j]);
return j;
}
```
## 三路快速排序(针对多个重复值把排序时间压缩到最短)
**针对多个重复值把排序时间压缩到最短,因为这种方法针对等于基准数的值就不用管,不用像前两个方法一样还要划分到两部分内。同时针对重复并不是很多的情况排序时间也不会太长,基本上稍弱于双路快速排序!**
如图所示,三路排序用三个指针lt,gt,i,划定了三个范围。多了一个等于v的范围。**它的方法和不再是前后两端指针找到后交换,而是如果i找到小于基准数的值,就把它和lt+1交换,把它放到小于基准数组部分的下一个,如果i遍历的值大于基准数,就把放到gt-1,大于基准数组部分的前一个。然后等于的都让他放中间。**
![在这里插入图片描述]()
```cpp
//三路快速排序(最高效的排序)
template<typename T>
void quick3_sort(T arr[], int n){
srand((unsigned int)time(NULL));
//先换个名字
__quicksort(arr,0,n-1);
}
template<typename T>
void __quicksort3(T arr[],int L,int R){
//结束条件
//if(L>=R)return;
if(R-L<=15){
InsertSort_merge(arr,L,R);
return;
}
//随机选择一个临时基准数
swap(arr[L],arr[rand()%(R-L+1)+L]);
T v = arr[L];
//分成三部分,arr[L+1...lt]<v; arr[lt+1...i-1]=v; arr[gt...R]>v
//注意三个指针的起始位置
int lt=L;
int gt=R+1;
int i=L+1;
while(i<gt){
if(arr[i]<v){
swap(arr[i],arr[lt+1]);
lt++;
i++;
}else if(arr[i]>v){
swap(arr[i],arr[gt-1]);
gt--;
}else{
i++;
}
}
swap(arr[L],arr[lt]);
//对两边分别再用快速排序
__quicksort3(arr,L,lt-1);
__quicksort3(arr,gt,R);
}
```
## 汇总
```cpp
#include<iostream>
using namespace std;
#include<algorithm>
#include<ctime>
//void swap(int& a, int& b)
//{
// int temp = a;
// a=b;
// b=temp;
//}
//选择排序
template<typename T>
void selectSort(T arr[], int n){
for(int i=0; i<n; i++)
{
int min = i;
for(int j=i+1; j<n; j++)
{
if(arr[j]<arr[min])
min = j;
}
swap(arr[i],arr[min]);
}
}
/*----------------------------------------------------------*/
//原始插入排序
template<typename T>
void InsertSort1(T arr[], int n){
for(int i =1; i<n; i++){
for(int j=i;j>=1; j--){
if(arr[j]<arr[j-1])//!这里是关键,j和j-1比较!
swap(arr[j],arr[j-1]);
else
break;
}
}
}
//改进后的插入排序
template<typename T>
void InsertSort2(T arr[], int n){
for(int i =1; i<n; i++){
T e = arr[i];
int j;
for( j=i;j>=1 && e <arr[j-1]; j--){
arr[j]=arr[j-1];
}
arr[j] = e;
}
}
/*----------------------------------------------------------*/
//希尔排序
template<typename T>
void Shell_sort(T arr[], int n){
for(int gap = n/2; gap>0; gap/=2)
{
for(int i =gap; i<n; i++){
T e = arr[i];
int j;
for( j=i;j-gap>=0 && e <arr[j-gap]; j-=gap){
arr[j]=arr[j-gap];
}
arr[j] = e;
}
}
}
/*----------------------------------------------------------*/
//冒泡排序
template<typename T>
void maopao_sort(T arr[], int n){
for(int i=0;i<n-1;i++){
for(int j=0;j<n-1; j++){
if(arr[j]>arr[j+1])
swap(arr[j],arr[j+1]);
}
}
}
/*----------------------------------------------------------*/
//归并排序
template<typename T>
void merge(T arr[], int n){
//先给函数换个参数传递
_merge_sort(arr, 0, n-1);
}
template<typename T>
void _merge_sort(T arr[], int L,int R){
//利用递归方法,先找结束条件
//if(L>=R)return;
if(R-L<=15){
InsertSort_merge(arr,L,R);
return;
}
//先把数组分成两份
int mid = (L+R)/2;//R-L
//再分别对分成的两组进行归并排序
_merge_sort(arr, L, mid);
_merge_sort(arr,mid+1,R);
//最后对整体进行归并排序
if(arr[mid]>arr[mid+1])//不大于的时候其实已经排好了
_merge(arr, L,mid,R);
}
template<typename T>
void _merge(T arr[],int L,int mid,int R){
T* aux = new T [R-L+1];//建立临时数组
//T aux[R-L+1];
//把原数组的值赋值到临时数组
//并且新数组的下标是从0开始的
for(int i= L; i<=R; i++){
aux[i-L] = arr[i];
}
int i =L;
int j =mid+1;
for(int k=L;k<=R;k++){
//是i>mid,不是>j
if(i>mid){
arr[k]=aux[j-L];
j++;//!不要忘记!
}else if(j>R)
{
arr[k]=aux[i-L];
i++;//!!
}else if(aux[i-L]<aux[j-L]){
arr[k]=aux[i-L];
i++;
}else{
arr[k]=aux[j-L];
j++;
}
}
delete[] aux;
}
//改进后的适用于归并的插入排序
template<typename T>
void InsertSort_merge(T arr[], int L,int R){
for(int i =L+1; i<=R; i++){
T e = arr[i];
int j;
for(j=i;j>L && e <arr[j-1]; j--){
arr[j]=arr[j-1];
}
arr[j] = e;
}
}
/*----------------------------------------------------------*/
//自底向上的归并排序
template<typename T>
void mergeBU(T arr[], int n){
//第一层遍历是每次分组后的单组的元素个数
for(int sz=1; sz<=n; sz+=sz){
//每两个组进行一次归并排序处理
//i+sz<n保证了第二组的存在
//min()函数是为了不存在第二部分末尾的时候,就把末尾换成数组末尾
for(int i=0; i+sz<n;i+=sz+sz){
_merge(arr,i,i+sz-1,min(i+sz+sz-1,n-1));
}
}
}
/*----------------------------------------------------------*/
//快速排序原始形态
template<typename T>
void quick_sort(T arr[], int n){
srand((unsigned int)time(NULL));
//先换个名字
__quicksort(arr,0,n-1);
}
template<typename T>
void __quicksort(T arr[],int L,int R){
//结束条件
if(L>=R)return;
//srand((unsigned int)time(NULL));
//接下来找到中间值,下面有两种方法可选择!
int p = __patition2(arr,L,R);
//对两边分别再用快速排序
__quicksort(arr,L,p);
__quicksort(arr,p+1,R);
}
template<typename T>
int __patition(T arr[], int L, int R){
srand((unsigned int)time(NULL));
swap(arr[L],arr[rand()%(R-L+1)+L]);
//创建一个临时基准数
T v = arr[L];
//arr[L+1,....j]<v ; arr[j+1....i]>v
int j=L;
for(int i=L+1;i<=R;i++){
if(arr[i]<v){
swap(arr[i],arr[j+1]);
j++;
}
}
swap(arr[L],arr[j]);
return j;
}
template<typename T>
int __patition2(T arr[], int L, int R){
swap(arr[L],arr[rand()%(R-L+1)+L]);
//创建一个临时基准数
T v = arr[L];
//arr[L+1,....j]<v ; arr[j+1....i]>v
int i=L+1,j=R;
while(true){
//while(arr[j]>v && j>=L)j--;
//这里必须是i先循环,否则就会程序崩溃!
//循环结束就停在了左侧第一个大于基准数的地方
while(arr[i]<v && i<=R)i++;
//循环结束就停在了右侧第一个小于基准数的地方
//!j>=L+1,否则程序崩溃!
while(arr[j]>v && j>=L+1)j--;
//如果指针重合并越界了
if(i>j)break;
swap(arr[i],arr[j]);
i++;
j--;
}
swap(arr[L],arr[j]);
return j;
}
/*----------------------------------------------------------*/
//三路快速排序(最高效的排序)
template<typename T>
void quick3_sort(T arr[], int n){
srand((unsigned int)time(NULL));
//先换个名字
__quicksort(arr,0,n-1);
}
template<typename T>
void __quicksort3(T arr[],int L,int R){
//结束条件
//if(L>=R)return;
if(R-L<=15){
InsertSort_merge(arr,L,R);
return;
}
//随机选择一个临时基准数
swap(arr[L],arr[rand()%(R-L+1)+L]);
T v = arr[L];
//分成三部分,arr[L+1...lt]<v; arr[lt+1...i-1]=v; arr[gt...R]>v
int lt=L;
int gt=R+1;
int i=L+1;
while(i<gt){
if(arr[i]<v){
swap(arr[i],arr[lt+1]);
lt++;
i++;
}else if(arr[i]>v){
swap(arr[i],arr[gt-1]);
gt--;
}else{
i++;
}
}
swap(arr[L],arr[lt]);
//对两边分别再用快速排序
__quicksort3(arr,L,lt-1);
__quicksort3(arr,gt,R);
}
int main(){
int n=7;
int arr[7]={10,2,0,3,9,1,7};
quick3_sort(arr,n);
for(int k=0; k<n; k++)
{
//cout<<"排序后:"<<endl;
cout<<arr[k]<<" ";
}
while(1);
return 0;
}
```
标签: #数组下标能为负数吗