バブルソート
1.隣接する2つの要素を比較します。前の要素が次の要素よりも大きい場合は、位置を入れ替えます。
2.最初の比較の後、最後の要素が最大の要素になります。
3.この時点では、最後の要素が最大であるため、最後の要素を比較に含める必要はありません。
実現原理
配列
n
に番号があり、隣接する2つの番号ごとに比較し、前者が後者よりも大きい場合は、2つの番号の位置を入れ替えます。このようにして、最初のラウンドで最大の番号を選択して、 end;次に、n-1
(配列の長さ-1)ラウンドの後、すべての数値のソートが完了します。
さて、最初に配列の最大数を見つけて、それを配列の最後に置きましょう。
var arr = [3,4,1,2];
// 遍历数组,次数就是arr.length - 1
for (var i = 0; i < arr.length - 1; i++) {
// 如果前一个数 大于 后一个数 就交换两数位置
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
console.log(arr) // [3, 1, 2, 4]
配列の中で最大の数を見つけて最後に配置します。arr.length-1回繰り返すと、配列を昇順で並べることができます。
var arr = [3,4,1,2];
// 遍历数组,次数就是arr.length - 1
for (var j = 0; j < arr.length - 1; j++) {
// 这里 i < arr.length - 1 ,要思考思考合适吗?我们下面继续说
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
console.log(arr) // [1,2,3,4]
上記のコードはバブルソートを実装していますが、コメントで述べたように、内側のforループの数はi <arr.length-1と書かれていますが、それは適切ですか?
考えてみましょう。最初に最大の数を見つけて最後に置いたとき、次にトラバースするときに最後の数を数えられないのでしょうか。最大のものであるため表示されず、前の番号が次の番号よりも大きく、位置を交換する必要があるため、内側のforループの数をi <arr.length-1-jに変更します。 、これは適切です。以下のコードを参照してください。
var arr = [3, 4, 1, 2];
function bubbleSort (arr) {
for (var j = 0; j < arr.length - 1; j++) {
// 这里要根据外层for循环的 j,逐渐减少内层 for循环的次数
for (var i = 0; i < arr.length - 1 - j; i++) {
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
return arr;
}
bubbleSort(arr);
元の配列が次の場合、この状況について考えます。
arr = [1,2,4,3];
バブルソートの最初のラウンドの後、配列は次のようになります。
arr = [1,2,3,4];
この時点で、配列は並べ替えられていますが、上記のコードに従って、配列は引き続き並べ替えられるため、フラグビットを追加します。特定のサイクル後に交換する2つの数値がない場合は、フラグビットを次のように設定します。 trueは、並べ替えが完了したことを示します。これにより、不要な並べ替えを減らし、パフォーマンスを向上させることができます。
挿入ソート方式(キューのカット)
ソートする配列を2つの部分に分割し、インデックスが最小の要素を後者の部分から前の部分の適切な位置に毎回挿入します。
- 最初の要素から始めて、要素はソートされたと見なすことができます。
- 次の要素を取り出し、並べ替えられた要素のシーケンスで後ろから前にスキャンします。
- 要素(ソート済み)が新しい要素よりも大きい場合は、要素を次の位置に移動します。
- ソートされた要素が新しい要素以下になる位置が見つかるまで、手順3を繰り返します。
- 新しい要素をこの位置に挿入した後。
- 手順2〜5を繰り返します。
function InsertSort(arr) {
let len = arr.length;
let preIndex, current;
for (let i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while (preIndex >= 0 && current < arr[preIndex]) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = current;
}
return arr;
}
var arr = [3,5,7,1,4,56,12,78,25,0,9,8,42,37];
InsertSort(arr);
クイックソート
上記を読んだ後、データ量が多すぎて実際の作業で配列がより複雑になると、2回のトラバーサルで同時にパフォーマンスの問題が発生することがわかったかどうかはわかりません。パニック、私たちはまだクイックソート方法を使用して解決することができます、快速排序对冒泡排序的一种改进
実現の考え方は、配列の並べ替え問題は2つの小さな配列の並べ替え問題と見なされ、数値がベンチマーク(中央の数値)であり、ベンチマークよりも小さいものが左側に配置され、大きいものが配置されるというものです。ベンチマークよりも右側に配置され、各Aの小さな配列は、配列の最大長が2になるまで、再帰的に2つの小さな配列と見なされ続けることができます。
function quickSort(arr){
//如果数组长度小于1,没必要排序,直接返回
if(arr.length<=1) return arr;
//pivot 基准索引,长度的一半
let pivotIndex = Math.floor(arr.length/2);//奇数项向下取整
//找到基准,把基准项从原数组删除
let pivot = arr.splice(pivotIndex,1)[0];
//定义左右数组
let left = [];
let right = [];
//把比基准小的放left,大的放right
arr.forEach(element => {
if(element<pivot){
left.push(element)
}else{
right.push(element)
}
});
return quickSort(left).concat([pivot],quickSort(right))
}
var arr=[4,56,3,67,44,5,66];
console.log(quickSort(arr));//[3, 4, 5, 44, 56, 66, 67]
完全なコード
var arr = [3, 4, 1, 2];
function bubbleSort (arr) {
var max = arr.length - 1;
for (var j = 0; j < max; j++) {
// 声明一个变量,作为标志位
var done = true;
for (var i = 0; i < max - j; i++) {
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
done = false;
}
}
if (done) {
break;
}
}
return arr;
}
bubbleSort(arr);
パフォーマンス
時間計算量:平均時間計算量O(n n)、最良の場合O(n)、最悪の場合O(n n)
空間計算量:O(1)
安定性:安定
これは時間のかかるアルゴリズムの実行時間の複雑さを指す
空間の複雑さを含むプログラムメモリの所望の最終サイズ実行
、安定化手段の場合= B、B、フロント、依然としてBの前にソート
A場合、不安定手段= b、aはbの前にあり、ソート後に位置を交換できます
総括する
1.外側のforループはサイクル数を制御します
。2。内側のforループは2つの数値を交換し、毎回最大数を見つけて最後に配置し
ます。3。フラグビットを設定して不要なサイクルを減らします。
再帰
js再帰的実装
定義:
再帰的関数は、関数本体でこの関数を呼び出すことです。
再帰関数を使用する場合は、無限ループを回避するために関数の終了条件に注意を払う必要があります。
再帰的実現フォーム:
1。名前付き関数を宣言し、関数名で呼び出します
function f(a){
if(a<=1){
return 1
}else{
return a*f(a-1)
}
}
ただし、この使用により、関数名fの変更により、エラーが発生します。
f = null
f () // Uncaught TypeError: f is not a function
- 関数名の代わりにarguments.calleeを使用する
Arguments.calleeはstrictモードではサポートされていません
3.関数式を使用する
var fun = (function f(a){
if(a<=1){
return 1
}else{
return a*f(a-1)
}
})
// 或:
var f = function (a){
if(a<=1){
return 1
}else{
return a*f(a-1)
}
}
var fun = f;
再帰的な戻り値
1.再帰関数は一種の循環呼び出しと同等であり、無限ループを回避し、条件が与えられた場合に呼び出しを停止する必要があります。
2.再帰関数の戻り値は、関数全体を返す必要があります
// 返回公约数的数组集合
let fun = (function f(a,n = 1,b=[]){
if(a%n === 0) {
b.push(n)
}
n ++;
if(n>a){
return b
}
return f(a,n,b) // *** 要返回整个函数,不能只是return b
})
调用函数
fun(4)
[1, 2, 4]
***で関数全体を返すには、
これは、実行条件n> aが確立されていない場合、戻り値がないためです。たとえば、最初の実行がn = 1、a = 4、1> 4がfalseの場合、戻り値はなく、後続の値は返されません。
// 可以参考这种形式,有return fun
fun (){
return fun(){
return fun(){
return 4
}
}
}
// 可以参考这种形式,没有return fun
fun (){
fun(){
fun(){
return 4
}
}
}