面经-快排,堆排序 稳定与否

177 阅读2分钟

快排

v2-2cfd5cedafd48dd88622876b185f8d11_1440w.jpg

image.png

v2-2586b672d2b78f583c29f6a6cfa10545_1440w.jpg

原理:先取第一个数为分水岭。。判断v[i]与分水岭得大小,小于和head互换,i++,head++ 。大于和tail互换,tail--。最终得到小于分水岭+分水岭+大于分水岭得数组,再对左边递归,得到最终结果。但是如果第一个数字的数值不好的情况下,可能复杂度到o(n^2)

右边递归,得到最终结果。

v2-221ac83a22eab597d2563d5116bc9dc7_1440w.jpg

v2-eca470602528324f14a505d258682250_1440w.jpg

v2-84e32b0b7c4735490f01d4a6799a5e41_1440w.jpg

func QuickSort(values []int) []int{
   length := len(values)
   if length <= 1 {
      return values
   }
   mid, i := values[0], 1    // 取第一个元素作为分水岭,i下标初始为1,即分水岭右侧的第一个元素的下标
   head, tail := 0, length-1 // 头尾的下标

   // 如果头和尾没有相遇,就会一直触发交换
   for head < tail {
      fmt.Println(values, head, tail, i)
      if values[i] > mid {
         // 如果分水岭右侧的元素大于分水岭,就将右侧的尾部元素和分水岭右侧元素交换
         values[i], values[tail] = values[tail], values[i]
         tail-- // 尾下标左移一位
      } else {
         // 如果分水岭右侧的元素小于等于分水岭,就将分水岭右移一位
         values[i], values[head] = values[head], values[i]
         head++ // 头下标右移一位
         i++    // i下标右移一位
      }
      fmt.Printf("----{head:%d,tail:%d,i:%d,mid:%d} values:%v\n", head, tail, i, mid, values)

   }

   // 分水岭左右的元素递归做同样处理
   QuickSort(values[:head])
   QuickSort(values[head+1:])
   return values
}

堆排序

func sortArray(arr []int)[]int  {
   length := len(arr)

   // 下沉建堆,从最后一个结点的父节点开始,往前遍历,执行建堆操作。。。。。大根堆
   for i := (length-1)/2;i>=0;i--{
      heapify(arr,length,i)

   }
   fmt.Println("构建大根堆结束",arr)
   //排序
   for k := length-1;k >= 0;k--{
      arr[0],arr[k] = arr[k],arr[0]//先交换首位,然后砍掉尾巴,做heapify
      heapify(arr,k,0)
      fmt.Println("排序过程",arr)
   }
   return arr
}

func heapify(arr []int,n,i int)  {
   if i >= n{
      return
   }
   c1 := 2*i+1
   c2 := 2*i+2
   max := i
   if(c1 < n && arr[c1] > arr[max]){
      max = c1
   }
   if (c2 < n && arr[c2] > arr[max]) {
      max = c2
   }
   if max != i{
      arr[max],arr[i] = arr[i],arr[max]
      heapify(arr,n,max)
   }
}

func main()  {
   var length = 10

   var tree []int

   for i := 0; i < length; i++ {
      tree = append(tree, int(rand.Intn(20)))
   }
   fmt.Println("原始数据",tree)
   arr := sortArray(tree)

   fmt.Println("排序完成",arr)

}

给定一个无序数组,首先通过heapify函数把它构造成大根堆。注意采用下沉建堆,从最后一个结点的父节点开始,往前遍历,执行建堆操作。。。。。大根堆。

heapify过程,传入arr,arr长度,构造大根堆父节点下标i。子节点大于父节点就互换位置,互换完位置,对子节点继续递归构造。。

构造完大根堆就去排序。。思路 对length进行for-循环。。先把首位互换,最大值扔到末尾,去构造新的大根堆。 注意这里的去尾操作不用刻意经行。在heapfy操作里,对子节点进行大小限制,c2 < n n就是最后一位的下标.

构建大根堆的时候,heapify的n带入length,i代表要处理位置的下标,所有的下标要小于length , c2 < n ,c1 < n

排序的时候,heapifiy的n带k:=length-1,,因为存在c2 < n ,c1 < n ,所以默认把大根的数的最后一个值给排除在外了。。

直接调用库函数

func sortArray(nums []int) []int {
    sort.Slice(nums,func(i,j int)bool{
        return nums[i]<nums[j]
    })
    return nums

}

选择排序

两个for循环 ,去比较,找到小的值

func selectionSort(arr []int)[]int {
   n := len(arr)

   for i := 0;i<n-1;i++{
      min := i
      for j := i;j<n;j++ {
         if arr[j] < arr[min]{
            min = j
         }
      }
      arr[i],arr[min] = arr[min],arr[i]

   }

   return arr

}

image.png v2-1a8e56b1548be3f0e646569e33aa2f33_1440w.png

冒泡排序


func Bubbles(arr []int)  {
   n := len(arr)
   for i := n-1;i>0;i--{
      for j := 0;j<n-1;j++{
         if arr[j] > arr[j+1]{
            arr[j],arr[j+1] = arr[j+1],arr[j]
         }
      }
   }
}

大for逆序,小for正序 第一轮 2-19111411414M58.gif 第二轮 2-191114114213154.gif

第三轮 2-191114114231129.gif 第四轮 2-19111411424RU.gif 第五轮 2-191114114311M1.gif

插入排序

func insertionSort(arr []int)[]int  {
   if arr == nil || len(arr) < 2{
      return arr
   }
   //0-0有序 0-i想有序
   for i := 1;i<len(arr);i++{
      for j := i-1;j >= 0 && arr[j]>arr[j+1];j-- {
         swap(arr,j,j+1)

      }
   }
   return arr
}

a6ea22d851bd4bf68e3ea4c3fa7ff5e1.png

image.png

就是前边递增,用新来的和前边有序数组进行比较,从后往前比较,啥时候小于他就互换位置

大for递增,小for递减 j := i-1;j >= 0 && arr[j]>arr[j+1];j--

归并排序

package main

import "fmt"
//双指针
//o(nlogn)
//先在中间位置把数组分开,给左右两边分别排序 之后再归并起来 归并之后的每一块都是有序的
func MergeSort(arr []int) []int {
   lenth := len(arr)

   //数组为空或者只有一个元素返回
   if lenth <= 1{
      return arr
   }
   mid := lenth/2
   leftArr := MergeSort(arr[:mid])
   rightArr := MergeSort(arr[mid:])
   
   return merge(leftArr,rightArr)
}

func merge(left []int,right []int)[]int  {
   var result  []int
   for len(left) != 0 && len(right) != 0{
      if left[0] < right[0]{
         result = append(result,left[0])
         left = left[1:]
      }else {
         result = append(result,right[0])
         right = right[1:]
      }
   }
   //把没有结束的归并过来
   for len(left) != 0 {
      result = append(result,left[0])
      left = left[1:]
   }
   for len(right) != 0 {
      result = append(result,right[0])
      right = right[1:]
   }
   return result
}
func main()  {
   arr := []int{20,5,3,1,2000,5,30}
   arr = MergeSort(arr)
   fmt.Println(arr)

}