基础指南 之 快速排序

**

快速排序

**
  快速排序是求职面试过程中问得最多的排序算法,相较于冒泡、插入排序等,快排复杂一些,而相较于堆排序等较难的排序,它又相对简单一些,下面开始介绍快排吧。

  1. 快排是利用分治的思想,从序列中取出一个基准元素,将整个序列划分成两部分,保证左半部分元素均小于(或等于)基准元素,右半部分元素均大于(或等于)基准元素,再将左右两部分子序列分别按照这个思路,取基准元素,将子序列的元素分成两个子序列,直至序列不可再分,便保证了整个序列的有序性。
  2. 将一个序列划分成小于基准元素的左半部分和大于基准元素的右半部分的过程称为一次划分(partition),数组上的划分程序如下所示:
int quick_sort_partition(int [] data,int left,int right)
{
    int priot=data[left];
    while(left < right)
    {
        while (left<right && data[right]>=priot)
            right--;
        data[left]=data[right];
        while(left<right && data[left]<=priot)
            left++;
        data[right]=data[left];
    }
    data[left]=priot;
    return left;
}

取序列中最左边的元素作为基准元素,left 和 right 分别为指向序列最左和最又的索引。移动 right 索引,从又向左找第一个小于基准的元素,将整个元素放在序列 left 索引位置;再移动 left 索引,从左向右找第一个大于基准的元素,将整个元素放在 right 索引位置;继续循环将小于基准的元素放到左边,将大于基准的元素放在右边,最后索引 left 和索引 right 相遇,将基准元素放在 left 索引位置,完成一次划分。
调用 partition 实现快速排序,有两种实现方式,递归的方式如下所示:

void quick_sort(int [] data,int left,int right)
{
    if(left<right)
    {
        int priot=quick_sort_partition(data,left,right);
        quick_sort(data,left,priot-1);
        quick_sort(data,priot+1,right);
    }
}

非递归的方式就是利用栈实现递归调用,如下所示:

void quick_sort_loop(int [] data,int left,int right)
{
    stack<int> st;
    if(left<right)
    {
        st.push(left);
        st.push(right);
        while(!st.empty())
        {
            int r=st.top();
            st.pop();
            int l=st.top();
            st.pop();
            int priot=quick_sort_partition(data,l,r);
            if(l<priot-1)
            {
                st.push(l);
                st.push(priot-1);
            }
            if(priot+1<right)
            {
                st.push(priot+1);
                st.push(r);
            }
        }
    }
}

单链表上的快排,划分程序如下所示:

struct Node
{
    int key;
    Node * next;
};

Node * partition(Node * begin,Node * end)
{
    Node * flag=begin;
    Node * scanner=begin->next;
    while(scaner!=end)
    {
        if(scaner->key<begin->key)
        {
            flag=flag->next;
            swap(flag->key,scanner->key);
        }
        scanner=scanner->next;
    }
    swap(flag->key,begin->key);
    return flag;
}

选取链表表头元素作为基准元素,利用两个指针 flag 和 scanner,指针 flag 记录小于小于基准元素的位置,指针 scanner 向前扫描元素寻找小于基准的新元素,将较小的元素与 flag 指针指向的下一个元素交换位置,并将 flag 指针指向新的位置。scanner 指针扫描到链表尾部后,将 flag 指针的指向元素的值与 基准元素(链表头)的值交换,到此便完成了一次划分,返回基准元素的新指针。
单链表上递归调用划分函数完成快排如下程序所示:

void qiuck_sort_link(Node * begin,Node * end)
{
    if(begin!=end)
    {
        Node * mid=partition(begin,end);
        qiuck_sort_link(begin,mid);
        qiuck_sort_link(mid->next,end);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值