堆排序,归并排序,复制随机指针链表

堆排序:

堆排序的思想就是先将待排序的序列建成大根堆,使得每个父节点的元素大于等于它的子节点。此时整个序列最大值即为堆顶元素,我们将其与末尾元素交换,使末尾元素为最大值,然后再调整堆顶元素使得剩下的 n-1n−1 个元素仍为大根堆,再重复执行以上操作我们即能得到一个有序的序列。

public int[] heapSort(int[] nums){
        if (nums==null||nums.length<2){
            return nums;
        }
        for (int i=0;i<nums.length;i++){
            heapInsert(nums,i);
        }
        int heapSize=nums.length;
        swap(nums,0,--heapSize);
        while (heapSize>0){
            heapify(nums,0,heapSize);
            swap(nums,0,--heapSize);
        }
        return nums;
    }
    public void heapInsert(int[] nums,int index){
        while (nums[index]>nums[(index-1)/2]){
            swap(nums,index,(index-1)/2);
            index=(index-1)/2;
        }
    }
    public void heapify(int[] nums,int index,int heapSize){
        int left=index*2+1;
        while (left<heapSize){//有左子树
            int largest=left+1<heapSize&&nums[left]<nums[left+1]?left+1:left;
            largest=nums[index]>nums[largest]?index:largest;
            if (largest==index){
                break;
            }
            swap(nums,largest,index);
            index=largest;
            left=index*2+1;
        }
    }

归并排序利用了分治的思想来对序列进行排序。对一个长为 n 的待排序的序列,我们将其分解成两个长度为 n/2,的子序列。每次先递归调用函数使两个子序列有序,然后我们再线性合并两个有序的子序列使整个序列有序。

public int[] mergeSort(int nums[],int l,int r){
        if (l==r){//只有一个元素没有必要去比较
            return null;
        }
        int mid=l+((r-l)>>1);
        mergeSort(nums,l,mid);//分治
        mergeSort(nums,mid+1,r);
        merge(nums,l,mid,r);//合并
        return nums;
    }

    private void merge(int[] nums, int l, int mid, int r) {
        int[] help=new int[r-l+1];
        int i=0;
        int p1=l;
        int p2=mid+1;
        while (p1<=mid&&p2<=r){
            help[i++]=nums[p1]<nums[p2]?nums[p1++]:nums[p2++];
        }
        while (p1<=mid){
            help[i++]=nums[p1++];
        }
        while (p2<=r){
            help[i++]=nums[p2++];
        }
        for (int j=0;j<help.length;j++){
            nums[l+j]=help[i];
        }
    }

方法一:利用哈希表的存储特性 

优点:思路清晰简单

缺点:需要额外的空间(哈希表)

class Solution {
    public Node copyRandomList(Node head) {
        //复制随机带指针的链表,我们可以利用哈希表的方式进行存储,key是原来的链表节点,value是复制的哈希表节点
        //然后通过循环链表,从哈希表中取出对应的复制节点,从而赋值给next和random
        HashMap<Node,Node> map=new HashMap<>();
        Node cur=head;
        while (cur!=null){//把所有节点全部压进哈希表
            map.put(cur,new Node(cur.val));
            cur=cur.next;
        }
        cur=head;
        Node newHead=map.get(head);//新的头节点
        Node last=newHead;//新链表的最后一个节点
        for (;cur!=null;cur=cur.next){
            last.next=map.get(cur.next);//next对应的复制节点
            last.random=map.get(cur.random);
            last=last.next;
        }
        return newHead;
    }
}

 方法二:合并再分割

 public Node copyRandomList(Node head) {
        //我们每遍历一个节点,就把他的复制节点插在它和它的next之中,那么我们复制节点的next就是原节点的next的下一个
        //同样的random节点也可以利用这种方式
        if (head==null){
            return null;
        }
        Node cur=head;
        while (cur!=null){
            Node next=cur.next;//记录下一个节点
            Node copyNode=new Node(cur.val);
            cur.next=copyNode;
            copyNode.next=next;
            cur=next;//因为复制节点的加入,一次需要跳两格
        }//循环结束说明链表的拼凑已经完成,我们需要对复制节点的random进行指向
        cur=head;
        while (cur!=null){
            Node next=cur.next.next;//原本cur的下一个节点
            cur.next.random=cur.random==null?null:cur.random.next;//把复制节点的random指向
            cur=next;
        }
        cur=head;
        Node newHead=cur.next;
        while (cur!=null){//拆开链表
            Node next=cur.next.next;
            cur.next.next=next!=null?next.next:null;
            cur.next=next;
            cur=next;
        }

        return newHead;
    }

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值