您的位置:首页 > 其它

插入,选择,交换,归并,基数排序

2014-01-05 14:12 411 查看
1. 插入排序
1.1 直接插入排序

(将后面的元素插入到前面已经排好的序列)

稳定;空间代价Θ(1),时间代价:Θ(n*n)

/****************** 直接插入排序 ******************/
template <class Record>
void ImprovedInsertSort (Record Array[], int n)
{
    //Array[] 为待排序数组,n 为数组长度

    Record TempRecord;          // 临时变量
    for (int i=1; i<n; i++)     // 依次插入第 i 个记录
    {
        TempRecord = Array[i];  //从 i 开始往前寻找记录 i 的正确位置
        int j = i-1;

        //将那些大于等于记录 i 的记录后移
        while ((j>=0) && (TempRecord < Array[j]))
        {
            Array[j+1] = Array[j];    //此时 j 后面就是记录 i 的正确位置,回填
            j = j - 1;
        }
        Array[j+1] = TempRecord;
    }
}


1.2 Shell 排序

(依次增量插入)

不稳定;空间代价Θ(1),时间代价:Θ(n*n)。Shell最好的增量,呈
2p3q 形式的一系列整数:1, 2, 3, 4, 6, 8, 9, 12

template <class Record>
void ModInsSort(Record Array[], int n, int delta)
{
    // 针对变化的增量而修改的插入排序算法,参数delta表示当前的增量
    Record TempRecord;				// 临时变量
    for (int i=delta; i<n; i+=delta)  		// 对子序列中第i个记录排序
    {
        TempRecord=Array[i];
        int j = i-delta;
        //从i开始往前寻找记录i的正确位置
        while (j>=0 && TempRecord < Array[j])
        {
            Array[j+delta] = Array[j];		   //将那些大于等于记录i的记录后移
            j = j - delta;
        }
        Array[j+delta] = TempRecord; 		   //此时j后面就是记录i的正确位置,回填
    }
}

template <class Record>
void ShellSort(Record Array[], int n)   	   //Shell排序,Array[]为待排序数组,n为数组长度
{
    for (int delta=n/3; delta>=1; delta/=3)        //增量delta每次除以3递减
        for (int j=0; j<delta; j++)		   //分别对delta个子序列进行插入排序
            ModInsSort(&Array[j], n-j, delta);
    //如果增量序列不能保证最后一个delta间距为1, 安排下面这个扫尾性质的插入排序
    ModInsSort(Array, n, 1);
}


2. 选择排序
2.1 直接选择排序

(依次选择最小元素放到对应的位置)

不稳定;空间代价:Θ(1),时间代价:Θ(n2)

/****************** 直接选择排序 ******************/
template <class Record>
void SelectSort(Record Array[], int n)   	// 直接选择排序,Array[]为待排序数组,n为数组长度
{
    for (int i=0; i<n-1; i++)   			// 依次选出第i小的记录,即剩余记录中最小的那个
    {
        int Smallest = i;				    // 首先假设记录i就是最小的
        for (int j=i+1; j<n; j++)			// 开始向后扫描所有剩余记录
            if (Array[j] < Array[Smallest])
                Smallest = j;			    // 如果发现更小的记录,记录它的位置

        // 交换Array[i]和 Array[Smallest],第i小的记录到位
        if (Smallest != i)
        {
            Record temp = Array[Smallest];
            Array[Smallest] = Array[i];
            Array[i] = temp;
        }
    }
}
2.2 堆排序

(先堆化,然后取最大元素然后继续调整为大根堆)

不稳定;空间代价为 Θ(1),总时间代价为 Θ(nlog n)

/****************** 堆排序 ******************/
template <class T>
class MaxHeap
{
private:
    T* heapArray;							//存放堆数据的数组
    int CurrentSize;						//当前堆中元素数目
    int MaxSize;							//堆所能容纳的最大元素数目
public:
    MaxHeap(T* array,int num,int max);
    virtual ~MaxHeap() {};					//析构函数
    void BuildHeap();
    bool isLeaf(int pos) const;				//如果是叶结点,返回TRUE
    int leftchild(int pos) const;			//返回左孩子位置
    int rightchild(int pos) const;			//返回右孩子位置
    int parent(int pos) const;				//返回父结点位置
    bool Remove(int pos, T& node);			//删除给定下标的元素
    void SiftDown(int left);				//筛选法函数,参数left表示开始处理的数组下标
    void SiftUp(int position);			 	//从position向上开始调整,使序列成为堆
    bool Insert(const T& newNode);			//向堆中插入新元素newNode
    void MoveMax();							//从堆顶移动最大值到尾部
    T& RemoveMax();							//从堆顶删除最大值
};

template<class T>
MaxHeap<T>::MaxHeap(T* array,int num,int max)
{
    heapArray=array;
    CurrentSize=num;
    MaxSize=max;
    BuildHeap();
}

template<class T>
void MaxHeap<T>::BuildHeap()
{
    for (int i=CurrentSize/2-1; i>=0; i--)
        SiftDown(i);
}

template<class T>
bool MaxHeap<T>::isLeaf(int pos) const
{
    return (pos>=CurrentSize/2)&&(pos<CurrentSize);
}

template<class T>
int MaxHeap<T>::leftchild(int pos) const
{
    return 2*pos+1;						//返回左孩子位置
}

template<class T>
int MaxHeap<T>::rightchild(int pos) const
{
    return 2*pos+2;						//返回右孩子位置
}

template<class T>
int MaxHeap<T>::parent(int pos) const	//返回父节点位置
{
    return (pos-1)/2;
}

template<class T>
void MaxHeap<T>::SiftDown(int left)
{
    //准备
    int i= left;						//标识父结点
    int j= 2*i+1;						//标识关键值较小的子结点
    T	temp=heapArray[i];				//保存父结点
    //过筛
    while(j<CurrentSize)
    {
        if((j<CurrentSize)&&(heapArray[j]<heapArray[j+1]))
            j++;						//j指向右子结点
        if(temp<heapArray[j])
        {
            heapArray[i]=heapArray[j];
            i=j;
            j=2*j+1;					//向下继续
        }
        else break;
    }
    heapArray[i]=temp;
}

template<class T>
void MaxHeap<T>::SiftUp(int position)
{
    //从position向上开始调整,使序列成为堆
    int temppos=position;
    T temp=heapArray[temppos];
    int parentpos=0;
    if(temppos>0)
        parentpos=parent(temppos);
    while((temppos>0)&&(heapArray[parentpos]<temp))
    {
        heapArray[temppos]=heapArray[parentpos];
        temppos=parentpos;
        parentpos=parent(temppos);
    }
    heapArray[temppos]=temp;
}

template<class T>
bool MaxHeap<T>::Insert(const T& newNode)
{
    //向堆中插入一个结点
    if(CurrentSize==MaxSize)				//堆空间已经满
        return false;
    heapArray[CurrentSize]=newNode;
    SiftUp(CurrentSize);					//向上调整
    CurrentSize++;
}

template<class T>
T& MaxHeap<T>::RemoveMax()
{
    if(CurrentSize==0)
    {
        cout << "Can't Delete" << endl;
        return;
    }
    else
    {
        T temp=heapArray[0];					//取堆顶元素
        heapArray[0]=heapArray[CurrentSize-1];	//堆末元素上升至堆顶
        CurrentSize--;
        SiftDown(0);							//从堆顶开始筛选
        return temp;
    }
}

template<class T>
void MaxHeap<T>::MoveMax()
{
    if(CurrentSize==0)
    {
        return;  //堆为空
    }
    else
    {
        T temp=heapArray[0];					//取堆顶元素
        heapArray[0]=heapArray[CurrentSize-1];	//堆末元素上升至堆顶
        CurrentSize--;
        SiftDown(0);							//从堆顶开始筛选
        heapArray[CurrentSize]=temp;
    }
    return;
}

template<class T>
bool MaxHeap<T>::Remove(int pos, T& node)
{
    // 删除给定下标的元素
    if((pos<0)||(pos>CurrentSize))
        return false;
    heapArray[pos]=heapArray[--CurrentSize];	//指定元素置于最后
    SiftUp(pos);								//上升筛
    SiftDown(pos);								//向下筛
    node=heapArray[CurrentSize];
    return true;
}

//堆排序,Array[]为待排序数组,n为数组长度
template <class Record>
void HeapSort(Record Array[], int n)
{
    MaxHeap<Record> max_heap = MaxHeap<Record>(Array, n, n);	//建堆
    for (int i=0; i<n; i++)		 // 依次找出剩余记录中的最大记录,即堆顶
        max_heap.MoveMax();
}


3. 交换排序
3.1 冒泡排序

(通过依次比较相邻的两个元素,让最小元素排序往左边移动直到到达它的合适位置)

稳定;空间代价:Θ(1),平均时间代价均为 Θ(n2)

/****************** 冒泡排序 ******************/
template <class Record>
void BubbleSort(Record Array[], int n)   	// 优化的冒泡排序,Array[]为待排序数组,n为数组长度
{
    bool NoSwap;			// 是否发生了交换的标志
    for (int i=0; i< n-1; i++)
    {
        NoSwap = true;		// 标志初始为真
        for (int j=n-1; j>i; j--)
            if (Array[j] < Array[j-1])   	// 判断(Array[j-1],Array[j])是否逆置
            {
                Record temp = Array[j];
                Array[j] = Array[j-1];
                Array[j-1] = temp;
                NoSwap = false; // 发生了交换,标志变为假
            }
        if (NoSwap)  			// 如果没发生过交换,表示已排好序,结束算法
            return;
    }
}
3.2 快速排序

(选择一个轴值,把数组分成左边比轴值小,右边比轴值大的两个数组,然后继续分治)

不稳定;平均空间代价:Θ(log
n)(递归调用使用到栈);平均时间代价:Θ(nlog n);

/****************** 快速排序 ******************/
void swap(Record *Array, int &id1, int &id2)  // 交换数组中两个下标的值
{
    Record temp = Array[id1];
    Array[id1] = Array[id2];
    Array[id2] = temp;
}

int SelectPivot(int left, int right)    // 选择轴值,参数left,right分别表示序列的左右端下标
{
    return (left+right)/2;				// 选择中间记录作为轴值
}

template <class Record>
int Partition(Record Array[], int left, int right)  // 分割函数,分割后轴值已到达正确位置
{
    int l = left;								    //  l为左指针,r为右指针
    int r = right;
    Record TempRecord = Array[r];				    // 将轴值存放在临时变量中
    while (l != r)   							    // 开始分割,l,r不断向中间移动,直到相遇
    {
        // l指针向右移动,直到找到一个大于轴值的记录
        while (Array[l] <= TempRecord && r > l)	// 这里也可以把"<="改写为"<",反正不稳定
            l++;
        if (l < r)   						// 若l,r尚未相遇,将逆置元素换到右边的空位
        {
            Array[r] = Array[l];
            r--;							//  r指针向左移动一步
        }
        // r指针向左移动,直到找到一个小于等于轴值的记录
        while (Array[r] > TempRecord && r > l) 	// 这里也可以把">"改写为">=",减少记录移动
            r--;
        if (l < r)   						// 若l,r尚未相遇,将逆置元素换到左边的空位
        {
            Array[l] = Array[r];
            l++;							// l指针向右移动一步
        }
    }	//end while
    Array[l] = TempRecord;					// 把轴值回填到分界位置l上
    return l;								// 返回分界位置l
}

template <class Record>
void QuickSort(Record Array[], int left, int right) // Array[]为待排序数组,left,right分别为数组两端
{
    if (right <= left) 	return;				// 如果子序列中只有0或1个记录,就不需排序
    int pivot = SelectPivot(left, right); 	// 选择轴值
    swap(Array, pivot, right);   			// 分割前先将轴值放到数组末端
    pivot = Partition(Array, left, right);  // 分割后轴值已到达正确位置
    QuickSort(Array, left, pivot-1);  		// 对轴值左边的子序列进行递归快速排序
    QuickSort(Array, pivot +1, right); 		// 对轴值右边的子序列进行递归快速排序
}


4. 归并排序
(将数组划分为两个子序列,分别对每个子序列归并排序,然后合并有序子序列)
稳定;空间代价:Θ(n),平均时间代价均为 Θ(nlog n)

/****************** 归并排序 ******************/
template <class Record>
void Merge(Record Array[], Record TempArray[], int left, int right, int middle)  //归并过程
{
    for (int j=left; j<=right; j++) // 将数组暂存入临时数组
        TempArray[j] = Array[j];
    int index1=left;				// 左边子序列的起始位置
    int index2=middle+1;			// 右边子序列的起始位置
    int i=left;						// 从左开始归并
    while (index1 <= middle && index2 <= right)
    {
        //取较小者插入合并数组中
        if (TempArray[index1] <= TempArray[index2])	// 为保证稳定性,相等时左边优先
            Array[i++] = TempArray[index1++];
        else
            Array[i++] = TempArray[index2++];
    }
    while (index1 <= middle)						// 只剩左序列,可以直接复制
        Array[i++] = TempArray[index1++];
    while (index2 <= right) 						// 与上个循环互斥,直接复制剩余的右序列
        Array[i++] = TempArray[index2++];
}

template <class Record>
void MergeSort(Record Array[], Record TempArray[], int left, int right)
{
    //两路归并排序,Array[]为待排序数组,left,right分别为数组两端
    if (left < right)   							// 如果序列中只有0或1个记录,就不用排序
    {
        int middle=(left+right)/2;					//从中间划分为两个子序列
        MergeSort(Array,TempArray,left,middle);		//对左边一半进行递归
        MergeSort(Array,TempArray,middle+1,right);	//对右边一半进行递归
        Merge(Array, TempArray, left, right, middle);// 进行归并
    }
}

5. 分配排序和基数排序
不需要进行纪录之间两两比较,需要事先知道记录序列的一些具体情况

5.1 桶排序
(记录元素分布区间[0,max),把数据放入对应的桶,并计数。然后从后往前读取数据,查询桶中计数,判断具体位置.)
稳定;总的时间代价为 Θ(m+n),空间代价Θ(m+n),m为区间个数 (适合于 m 比较小的情况)
/****************** 桶排序 ******************/
template <class Record>
void BucketSort(Record Array[], int n, int max)
{
    // 桶式排序,Array[]为待排序数组,数组长度为n,所有记录都位于区间[0,max)上
    int* TempArray = new Record
;		// 临时数组
    int* count = new int[max];			// 小于或等于i的元素个数
    int i;

    for (i=0; i<n; i++)					// 把序列复制到临时数组
        TempArray[i] = Array[i];
    for (i=0; i<max; i++)				// 所有计数器初始都为0
        count[i] = 0;
    for (i=0; i<n; i++)					// 统计每个取值出现的次数
        count[Array[i]]++;
    for (i=1; i<max; i++)				// 统计小于等于i的元素个数
        count[i] = count[i-1]+count [i];
    for (i=n-1; i>=0; i--)				// 从尾部开始按顺序输出有序序列,保证排序的稳定性
        Array[--count[TempArray[i]]] = TempArray[i];
}

5.2 基数排序
(原理同桶排序一样,只是当 m 很大时,将一个记录的值即排序码拆分为多个部分来进行比较)
稳定;空间代价:Θ(n+r),时间代价:Θ(d·(n+r))
/****************** 基数排序 ******************/
template <class Record>
void RadixSort(Record Array[], int n, int d, int r)
{
    // 数组实现的基数排序,n为数组长度,d为排序码个数,r为基数
    // 如果对数字排序,d为最大数的位数,r一般为10
    Record *TempArray =new Record
;		// 辅助排序的临时数组
    int* count = new int[r];				// 桶容量计数器,count[i] 存储了第i个桶中的记录数
    int i,j,k;
    int Radix = 1;							// 模保持进位,用来取Array[j]的第i位排序码
    for (i=0; i<d; i++)   					// 分别对第i个排序码进行分配
    {
        for (j=0; j<r; j++)					// 初始计数器均为0
            count[j] = 0;
        for (j=0; j<n; j++)	  				// 统计每个桶中的记录数
        {
            k = (Array[j] / Radix) % r;		// 取Array[j]的第i位排序码
            count[k]++;						// 相应计数器加1
        }
        for (j=1; j<r; j++)					// 将TempArray中的位置依次分配给r个桶
            count[j] = count[j-1] + count[j];
        for (j=n-1; j>=0; j--)  			// 从数字尾部,把记录收集到相应桶
        {
            k = (Array[j] / Radix ) % r;	// 取Array[j]的第i位排序码
            count[k]--;						// 使用了第k个桶的一个位置,桶剩余量的计数器减1
            TempArray[count[k]] = Array[j];
        }
        for (j=0; j<n; j++)					// 将临时数组中的内容复制到Array中
            Array[j] = TempArray[j];
        Radix *= r;							// 往左进一位,修改模Radix
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐