冒泡排序与快速排序

189 阅读2分钟

冒泡

执行方式:

  • 1.比较相邻的俩个元素,第一个大于第二个,交换位置
  • 2对每个相邻的元素做同样的动作,从开始到最后一对,完成之后,最后一个元素是最大的
  • 3.重复上一个步骤,除了最后一个
  • 4.持续上述步骤,直到没有任何数字比较
5321

i = 0| 5>3  3 5 2 1
i = 1| 5>2  3 2 5 1
i = 2| 5>1  3 2 1 5
[0,len-1]

i = 0| 3>2  2 3 1 5
i = 1| 3>1  2 1 3 5
[0,len-1-1]

i = 0| 2>1  1 2 3 5
[0,len-1-1-1]
function sortArray(nums: number[]): number[] {
  let len = nums.length;
  if ((len <= 1)) {
    return nums;
  }

  for (let i = 0; i < len - 1; i++) {
    for (let j = 0; j < len - 1 - i; j++) {
      if (nums[j] > nums[j + 1]) {
          [nums[j],nums[j+1]] = [nums[j+1],nums[j]]
      }
    }
  }

  return nums
}

console.log(sortArray([5,3,2,1]));

时间复杂度为:O(n^2) 空间复杂度为:因为是俩俩交换,没有改变位置。 O(1)

快排

思路:分区交换排序,把一个序列分为较小和较大2个子序列,递归排序2个子序列

  • 1.基准值:从数列中挑出一个元素
  • 2.分割,比基准值小的放基准前面,大的放后面,相等的随便
  • 3.递归排序子序列:递归将小于基准值元素的子序列和大于基准值的子序列排序
  • 判断条件,递归到底部时数列的大小为0||1
quickSort(nums,left:左边的下标,right:右边的下标)

25743698

p:3
2 3 574698

p:6
23  54 6 798

p1:4  p2: 9
23 4 5 6 78 9

「简版」

function quickSort(nums: number[]): number[] {
  if (nums.length <= 1) {
    return nums;
  }
  let p = nums[Math.floor(nums.length / 2)];
  let leftList = [];
  let rightList = [];
  for (let i = 0; i < nums.length; i++) {
    if (nums[i] < p) {
      leftList.push(nums[i]);
    }
    if (nums[i] > p) {
      rightList.push(nums[i]);
    }
  }

  console.log(p, leftList, rightList);
  return quickSort(leftList).concat([p], quickSort(rightList));
}

console.log(quickSort([2, 5, 7, 4, 3, 6, 9, 8]));

「复杂版」

sortArray([2, 5, 7, 4, 3, 6, 9, 8]);
function sortArray(nums: number[]) {
  let len = nums.length;
  if (len <= 1) {
    return nums;
  }

  sort(nums, 0, len - 1);
  function sort(nums: number[], left: number, right: number) {
    if (left < right) {
      //获取基准的下标
      let pIndex = getPivot(nums, left, right);
      //左子序列,此序列必定比p(基准值)小
      sort(nums, left, pIndex - 1);
      //右子序列,此序列必定比p(基准值)大
      sort(nums, pIndex + 1, right);
    }
  }

  function getPivot(nums: number[], left: number, right: number) {
    let p = nums[left];//默认基准为最左边的数
    let i = left;
    let j = right + 1;//因为数组最后一个元素也要参与比较,如果是下标经过--j那就是往左一个元素和nums[i]比较

    //i和j要从俩边遍历和p对比,那么当i>=j的时候数组的元素就都和p比较过了。所以结束条件为i>=j
    while (1) {
        //从左向右遍历,当i>p的时候,i左边的元素必定都是小于p的元素
      while (nums[++i] < p) {
        if (i === right) {
          break;
        }
      }
      //从右向左遍历,当j<p的时候,j右边的元素必定都是大于p的元素
      while (nums[--j] > p) {
        if (j === left) {
          break;
        }
      }
      if (i >= j) {
        break;
      }
      //i<j,说明i和j之间还有没比较的元素,先对比一下i和j。
      //因为nums[i]<p,nums[j]>p,当他俩交合说明交合处坐标的左边小于p,右边大于p
      //所以基准坐标必定在i和j的交界处,所以nums[i]<nums[j]不满足就替换
        [nums[i], nums[j]] = [nums[j], nums[i]];
    }
    //j就是基准坐标,基准值nuns[left]就该放到j的位置,因为i>=j,此时nums[j]必定小于基准
    [nums[left], nums[j]] = [nums[j], nums[left]];
    return j;
  }
}

export {}

「运行过程」

5(p)(i),4,3,2,6,undefined(j)
num[++i] < p
4 < 5 i=1
3 < 5 i=2
2 < 5 i=3
6 > 5break】 i=4
nums[--j] >p
6 > 5  j=4
2 < 5break】j=3
i > j
nums:24356

2(p)(i) 4 3,undfined(j)
num[++i] < p
4 > 2break】i=1
nums[--j] >p
3 > 2 j=2
4>2 j=1
2=2break】j=0
i>j
nums:24356

4(p)(i) 3 undfined(j)
num[++i] < p
3 < 4 i=1
und 【break】i=2
nums[--j] >p
3 < 4break】j=1
i > j
nums:23456

时间复杂度:O(nlogN) 空间复杂度:O(logN)