shell 数组 与 排序


一、数组

注意:使用、遍历数组的时候,数组格式要写成 ${arr[@]} 或 ${arr[*]}

1.1 数组定义

在这里插入图片描述

数组的四种定义方法:

方法一:
#默认数组下标从0开始
数组名=(value0 value1 value2 ... 

方法二:
#数组下标索引可以自己设置
数组名=[0]=value [1]=value [2]=value ... 

方法三:
先定义列表名,再转成数组
列表名="value0 value1 value2 ..."
数组名=($列表名)

方法四:
#一般用于for/while循环进行复制
数组名[0]="value"
数组名[1]="value"
数组名[2]="value"
...

数组的数据类型:

  • 数值类型
  • 字符类型:使用 " " 或 ’ ’ 来定义

获取数组长度:

arr=(1 2 3 400 5)
arr_len=${#arr[*]}

arr_len=${#arr[@]}

输出下标为3的元素的长度
arr_len=${#arr[3]}

获取数组列表:

输出整个数组
echo ${arr[*]}   echo $arr{[@]}

输出字符中某个元素
echo ${arr[下标]} 

输出数组中一部分元素
echo ${arr[*]:下标:长度}    echo ${arr[*]:2:3}
是先输出数组,然后在这个结果上再去取

遍历数组元素

arr1=(1 2 3 4 5)
for i in ${arr1[@]}
do
	echo $i
done

修改数组

修改数组元素的值,将arr1下标2的元素值为30
arr1[2]=30

将一个数组的值赋给另一个数组
arr3=${arr1[@]}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 数组元素替换与删除

替换

#${数组名[@或*]/查找字符/替换字符}
echo ${arr1[@]/4/66} 

#替换只是临时替换,并不会替换数组原有内容
echo ${arr1[@]}

#要实现改变原有数组,可通过替换后 重新赋值实现
arr5=(${arr1[@]/4/66})
echo ${arr[@]}

注:通过上面重新赋值有个问题,会把原来所有的元素当成 arr5[0] 的一个元素,arr5[1] 没有值。

在这里插入图片描述
数组删除

arr=(1 2 3 4 5)
unset arr[2]      #删除第三个元素
unset arr         #删除整个数组

在这里插入图片描述

1.3 数组追加元素

【方法一】
直接赋值,index是数组中的新下标
array_name[index]=value


【方法二】
和方法一一样,用${#}获取数组长度作为新增的数组下标
array_name[${#array_name[@]}] =value


【方法三】
在现有数组的基础上,在后面追加元素,赋给新数组
array_name=("${array_name[@]}" value1 ... valueN)

注意,使用方法三时:
1. 参数中的 双引号不能省略,否则,当数组 array_name 中包含空格的元素时会按空格将元素拆分成多个
2. 也不能将 [@] 替换成 [*] ,如果替换为 [*],不加双引号时与 [@] 时的表现一致
   加双引号时,会将数组array_name中的所有元素作为一个元素添加到数组中。
   
   
【方法四】
在现有数组的基础上,在后面追加元素
array_name+=(value1 ... valueN)
注意:待添加元素必须用 () 括号包围起来,并且多个元素用空格分隔

在这里插入图片描述
方法三测试
在这里插入图片描述
在这里插入图片描述
正确的应该给原数组 加上 双引号 “”

在这里插入图片描述
此时用 for 遍历的话,需要给数组加双引号,来遍历 @,因为有个带空格的元素,
在这里插入图片描述

二、将数组作为参数传给函数

注意:如果只将数组名作为变量传给函数,函数只会取数组变量的第一个元素。

观察下面执行的结果:

function fun1(){
        echo "函数收到的数组为:$@"
        newarr=($1)
        echo "函数新数组的值为:${newarr[@]}"
}

#####
arr=(10 20 30 40 50)
echo "原始数组为:${arr[@]}"

fun1 ${arr[@]}    #将整个数组的值作为函数的参数

在这里插入图片描述
解决这个问题则需要:

  • 将数组变量的值分解成单个的值,然后将这些值作为函数的参数。
  • 然后在函数内部,再将所有的参数重新组合成一个新的数组变量。
function fun1(){
        echo "函数收到的数组为:$@"
        #newarr=($(echo $@))       #()用来提取 里面命令执行的结果
        newarr=($@)
        #newarr=($2)
        echo "函数新数组的值为:${newarr[@]}"
}

#####
arr=(10 20 30 40 50)
echo "原始数组为:${arr[@]}"

fun1 ${arr[@]}

在这里插入图片描述

大致步骤为:
1. 先讲数组拆分成列表 ${arr[@]}
2. 函数通 $@ 获取之前将数组拆分成后列表的值
3. 在函数中重新把列表定义成数组 newarr=($@)
4. 在对新的数组进行处理,最后echo返回结果

小测试:将一个数组中的值全部乘以2后输出。

function test1(){
	newarr=($@)   #列表转成数组
	sum=0
	for i in ${newarr[@]}
	do
		sum=$[$sum+$i]   #遍历数组元素进行相加
	done
	echo $sum
}

function test2(){
	newarray=($@)     #列表转成数组
	
	#length=${#newarray[@]}
	#for ((i=0; i<=$length-1; i++))
	
	for ((i=0; i<=$[$# - 1]; i++))
	do
		newarray[$i]=$[${newarray[$i]}*2]   #每个元素乘以2后再赋给该元素
	done
	echo ${newarray[*]}  #返回整个数组
}

#####
arr=(1 3 6 10 8)
echo "原始数组为:${arr[@]}"

result=`test1 ${arr[*]}`
echo "新数组的和为:"$result

newarray=`test2 ${arr[*]}`       #获取整个数组
#newarray=(`test2 ${arr[*]}`)
echo "新数组乘以二后为:"${newarray[*]}    #输出数组

在这里插入图片描述

三、数组排序算法

2.1 冒泡排序

https://www.cnblogs.com/xaimicom/p/9189471.html
在这里插入图片描述

 冒泡排序的原理是类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动。

基本思想:

 冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。

算法思路:

 冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减少。

 结就是:当前比较次数比上一次少比较一次(因为最大的已经找出来放到最后(前)面了)

代码实现:

#arr=(8 5 9 3 4)
read -p "请输入一个数组:" arry

#列表转数组,获取数组长度
arr=($arry)
length=${#arr[@]}

#定义比较轮数,长度-1,比如五个数,比较四轮即可
for ((i=1; i<$length; i++))
do
        #确定内次比较的次数,随着i的增大而降低,因为每轮比较后,最大/小的数已经在末尾了
        for((j=0; j<$length-$i; j++))
        do
                #获取每次用于比较的第一个、第二个数
                first=${arr[$j]}
                k=$[$j+1]
                second=${arr[$k]}
                #比较,如果前一个比后一个数大,则替换,如果是 if [ $first -lt $second ];then,则从大到小排序
                if [ $first -gt $second ];then
                        tem=${arr[$j]}
                        arr[$j]=${arr[$[$j+1]]}
                        arr[$[$j+1]]=$tem
                fi

        done
done

echo "从小到大排序为:"${arr[@]}

在这里插入图片描述
可以用函数实现,先讲输入的列表传入函数,函数再从列表转为数组

#冒泡排序函数
function bubblesort(){

#列表转数组,获取数组长度
arr=($@)
length=${#arr[@]}

#定义比较轮数,长度-1,比如五个数,比较四轮即可
for ((i=1; i<$length; i++))
do
	#确定内次比较的次数,随着i的增大而降低,因为每轮比较后,最大/小的数已经在末尾了
	for((j=0; j<$length-$i; j++))
	do
		#获取每次用于比较的第一个、第二个数
		first=${arr[$j]}
		k=$[$j+1]
		second=${arr[$k]}
		#比较,如果前一个比后一个数大,则替换,如果是 if [ $first -lt $second ];then,则从大到小排序
		if [ $first -gt $second ];then
			tem=${arr[$j]}
			arr[$j]=${arr[$[$j+1]]}
			arr[$[$j+1]]=$tem
		fi		
	done
done

echo ${arr[@]}
}

################## main ###############
#arr=(8 5 9 3 4)
read -p "请输入一个数组:" arry
bubble_result=`bubblesort $arry`
echo "从小到大重新排序后为:"${bubble_result[@]}

2.2 直接选择排序

直接选择排序:

 与冒泡排序相比,直接选择排序的交换次数更少,所以速度会快些。

基本思想:

 将指定排序位置与其它数组元素分别对比,如果满足条件就交换元素值,注意这里区别冒泡排序,不是交换相邻元素,而是把满足条件的元素与指定的排序位置交换(如从最后一个元素开始排序),这样排序好的位置逐渐扩大,最后整个数组都成为已排序好的格式。

 首先记录第一个元素的下标为 index,与下一个元素进行比较,如果下一个元素大于当前i ndex元素的值,就把大的元素的下标给 index,然后 index 继续与下一个元素进行比较,继续判断,直到元素都判断完毕。此时 下标为 index 的就是最大的元素,并放到了最后的位置上。

代码实现:

#直接选择排序函数
function selectsort(){
	#列表转换成数组
	arr=($@)
	length=${#arr[@]}
	
	for((i=1; i<$length; i++))       #定义排序轮训次数,比如五个数只要排序四趟
	do
		index=0
		#确定当前排序 实际最大元素的下标,从第二个元素开始比较,每次都比上次少比一次
		for((j=1; j<=length-i; j++))
		do
			if [ ${arr[$j]} -gt ${arr[$index]} ];then     #如果是从大到小,用 -lt
				index=$j	#如果下一个比当前index大,就把大的值给index
			fi
		done
		#遍历完成,此时下标为index的 就是当前最大的元素
		#把当前比出来的index元素的值 和当前轮循的最后一个元素进行替换
		k=$[$length-$i]
		tmp=${arr[$k]}
		arr[$k]=${arr[$index]}
		arr[$index]=$tmp
	done
	#别忘了返回数组
	echo ${arr[@]}
}

########## mian ##########
read -p "请输入一个数组:" arry
#将列表传给选择排序函数,并获取返回的数组值
select_rest=`selectsort $arry`
echo "选择排序后的数组为:"${select_rest[@]}

在这里插入图片描述

2.3 数组反转

反转排序

 以相反的顺序把原有数组的内容重新排序。

基本思想:

 把数组最后一个元素与第一个元素替换,倒数第二个元素与第二个元素替换,以此类推,直到把所有数组元素反转替换,如果是奇数,中间的不动。

代码实现:

#数组反转函数
function reversal(){
        arr=($@)
        length=${#arr[@]}
        for((i=0; i<$length/2; i++))
        do
                #第一个与倒数第一个替换,第二个与倒数第二个替换
                tmp=${arr[$i]}
                arr[$i]=${arr[$length-1-i]}
                arr[$length-1-i]=$tmp
        done
        echo ${arr[@]}
}

#############main##########
read -p "请输入一个数组:" arry
result=`reversal $arry`
echo "反转后的数组为:"${result[@]}

在这里插入图片描述

2.4 希尔排序

 1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。

算法描述:

 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

  • 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  • 按增量序列个数k,对序列进行k 趟排序;
  • 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

 希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。

在这里插入图片描述

代码实现:

java 代码
function shellSort(arr) {
    varlen = arr.length;
    for(vargap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
        //多个分组交替执行
        for(vari = gap; i < len; i++) {
            varj = i;
            varcurrent = arr[i];
            while(j - gap >= 0 && current < arr[j - gap]) {
                 arr[j] = arr[j - gap];
                 j = j - gap; 
            }
            arr[j] = current;
        }
    }
    returnarr;
}

arr[]={6 5 2 1 8 4}
shellSort(arr)

array=(7 6 8 3 1 5 2 4)
length=${#array[*]}

#把距离为gap的元素编为一个组,扫描所有组,每次循环减少增量
for ((gap=$length/2; gap>0; gap/=2))
do
    for ((i=gap; i<$length; i++))
    do
          temp=${array[$i]}
          #对距离为gap的元素组进行排序,每一轮比较拿当前轮次最后一个元素与组内其他元素比较,将数组大的往后放
          for ((j=i-gap; j>=0&&temp<${array[$j]}; j-=gap))
          do
              array[$j+$gap]=${array[$j]}
          done
          #和最左边较大的元素调换位置
        array[$j+$gap]=$temp
    done
done

echo ${array[*]}

比如数组为 4 5 1 6 2 3
带了最后一次循环时,数组为 1 2 4 5 6 3,
最后一次执行步骤结果为:
1 2 4 5 6 3
1 2 4 5 6 6
1 2 4 5 5 6
1 2 4 4 5 6
1 2 3 4 5 6

参考链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值