shell 数组 与 排序

Posted 我一个月改一次名

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 #######以上是关于shell 数组 与 排序的主要内容,如果未能解决你的问题,请参考以下文章

shell脚本中的数组排序

shell之数组

markdown 数组排序片段

shell实现简单的数组排序

数据结构与算法之--高级排序:shell排序和快速排序未完待续

Shell编程之函数与数组