堆结构与堆排序

前置基础:

1、向上调整大根堆

已知数组arr,它的排列顺序为大根堆时,加入一个新的数,如何能让整个数组的排列顺序变成大根堆?

public static void heapinsert(int i) {
     while (arr[i] > arr[(i - 1) / 2]) {   //下标(i - 1) / 2为下标i的父节点
         swap(i, (i - 1) / 2);
         i = (i - 1) / 2;
     }   
}

public static void swap(int i, int j) {
    int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}

  向上调整大根堆,时间复杂度为O(logN)。

2、向下调整大根堆

已知数组arr,它的排列顺序为大根堆时,第一个数变笑了,如果调整使它重新变成大根堆?

public static void heapify(int i, int size) { //size表示这个数组大根堆中节点的个数
    int l = i * 2 + 1;
    while (l < size) {
        int best = l + 1 < size && arr[l+1] > arr[l] ? l+1 : l;
        best = arr[best] > arr[i] ?  best : i;
        if (best == i) {
            break;
        }
        swap(i, best);
        i = best;
        l = i * 2 + 1;
    }
}

public static void swap (int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;    
}

向下调整大根堆,时间复杂度为O(logN)。

堆排序

堆排序java代码

public class HeapSort {
    public static int MAXN = 100001;

	public static int[] arr = new int[MAXN];

	public static int n;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StreamTokenizer in = new StreamTokenizer(br);
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		in.nextToken();
		n = (int) in.nval;
		for (int i = 0; i < n; i++) {
			in.nextToken();
			arr[i] = (int) in.nval;
		}
		// heapSort1();
		heapSort2();
		for (int i = 0; i < n - 1; i++) {
			out.print(arr[i] + " ");
		}
		out.println(arr[n - 1]);
		out.flush();
		out.close();
		br.close();
	}
    
    public static void heapinsert(int i) {
         while (arr[i] > arr[(i - 1) / 2]) {   //下标(i - 1) / 2为下标i的父节点
             swap(i, (i - 1) / 2);
             i = (i - 1) / 2;
         }   
    }

    public static void heapify(int i, int size) { //size表示这个数组大根堆中节点的个数
        int l = i * 2 + 1;
        while (l < size) {
            int best = l + 1 < size && arr[l+1] > arr[l] ? l+1 : l;
            best = arr[best] > arr[i] ?  best : i;
            if (best == i) {
                break;
            }
            swap(i, best);
            i = best;
            l = i * 2 + 1;
        }
    }

    public static void swap(int i, int j) {
        int tmp = arr[i];
	    arr[i] = arr[j];
	    arr[j] = tmp;
    }


    //从顶到底建立大根堆过程,时间复杂度O(NlogN);
    //交换并向下调整大根退过程,时间复杂度O(NlogN);
    //故总体的时间复杂度O(NlogN);
    public static void heapSort1 () {
        //从顶到底建立大根堆
        for (int i = 0; i < n; i++){
            heapinsert(i);
        }
        //大根堆的第一个数一定是最大的数,将其与最后一个位置交换
        int size = n;
        while (size > 1) {
            swap(0, --size);
            heapify(0, size);
        }
    }

    //从底到顶建立大根堆过程,时间复杂度O(NlogN);
    //交换并向下调整大根退过程,时间复杂度O(NlogN);
    //故总体的时间复杂度O(NlogN);
    public static void heapSort2() {
        //从底到顶建立大根堆
        int size = n;
        for (int i = n - 1; i >= 0; i--) {
            heapify(i, size);
        }
        //大根堆的第一个数一定是最大的数,将其与最后一个位置交换
        while (size > 1) {
            swap(0, --size);
            heapify(0, size);
        }   

    }
}

从顶到底建立大根堆时间复杂度证明

从底到顶建立大根堆时间复杂度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值