【算法】内部排序(8种)算法实现

C/C++代码实现8种内部排序

#include<iostream>
using namespace std;

int n;//元素个数
const int maxn = 100;//最大元素个数

int R[maxn / 2 + 2];//右子表 
int L[maxn / 2 + 2];//左子表 
const int inf = 0x7ffff;

void InsertSort(int r[])
{

    //gap = 1的shell sort
    for (int i = 2; i <= n; i++)
    {
        if (r[i] < r[i - 1])
        {
            r[0] = r[i];
            r[i] = r[i - 1];//向后移动

            int j = i - 2;
            while (r[0] < r[j]) //若是r[0]比r[j]小
            {
                r[j + 1] = r[j];//r[j]向后移动
                --j;//向前找比r[0]大的记录
            }//r[0] >= r[j]
            r[j + 1] = r[0];
        }
    }
}

void BiInsertSort(int r[])
{
    for (int i = 2; i <= n; i++)
    {
        r[0] = r[i];
        int low = 1;
        int high = i - 1;
        while (low <= high)
        {
            //int mid = (high + low) / 2;
            //防止溢出
            int  mid = high - (high - low) / 2;
            if (r[0] < r[mid])
                high = mid - 1;
            else low = mid + 1;
        }

        int j = i - 1;
        while (j >= high + 1)
        {
            r[j + 1] = r[j];
            --j;
        }//j < hight + 1  j == high
        r[j + 1] = r[0];
    }
}

void ShellInsert(int r[], int gap)
{
    for (int i = gap + 1; i <= n; i++)
    {
        if (r[i] < r[i - gap])
        {
            r[0] = r[i];
            int j = i - gap;
            while (j > 0 && r[0] < r[j])
            {
                //向后移动元素
                r[j + gap] = r[j];
                j -= gap;
            }
            r[j + gap] = r[0];
        }
    }

}

/*
希尔排序
delta数组是间隔数组 每个元素代表间隔gap大小
t表示delta数组的元素个数
*/
void ShellSort(int r[], int delta[], int t)
{
    for (int i = 0; i < t; i++)
    {
        ShellInsert(r, delta[i]);//对每一组子序列进行插入排序
    }
}

/*冒泡排序*/
void BubbleSort(int r[])
{
    for (int i = 1; i < n; i++) //n - 1趟 
    {
        for (int j = 1; j <= n - i; j++) //每趟排序会将一个最大值浮到最后面
        {
            if (r[j + 1] < r[j])//交换 将大数放在后面 
            {
                int t = r[j + 1];
                r[j + 1] = r[j];
                r[j] = t;
            }
        }
    }
}
void Swap1(int* p, int* q) {
	//下面这种方法可以实现实参值的交换 因为传递的是实参a b的地址 
	//p指向a q指向b *p = a的值 可以通过修改*p来修改指向内存地址单元的值 
	//p是int *类型(此函数中形参)  *p 是int类型 
    int temp;
    temp = *p;
    *p = *q;
    *q = temp;
    
    //下面这种方法并不能交换实参值 函数传递的是实参a b地址 
	//因为它只是交换了p q的的值 p指向b的地址 q指向a的地址 并没有改变实参的值
//    int *t = p;
//    p = q;
//    q = t;
}

void Swap2(int& p, int& q) {//引用  传递的是地址 
    int temp = p;
    p = q;
    q = temp;
}

/*排列高低子表元素 最后确定枢轴位置*/
int  Partition(int r[], int low, int high)
{
    int pivotkey = r[low];//枢轴记录为r[low]

    while (low < high) {
        while (low < high && r[high] >= pivotkey) {
            high--;
        }//r[high] < pivotkey

        //交换high和low指向的记录
        Swap1(&r[high], &r[low]);
        //Swap2(r[high], r[low]);

        while (low < high && r[low] <= pivotkey) {
            low++;
        }//r[low] > pivotkey

        //交换low和high指向的记录
        Swap1(&r[low], &r[high]);
    }
    return low;
}

/*快速排序*/ 
void QuickSort(int r[], int low, int high) {
    if (low < high)
    {
        int pivotloc = Partition(r, low, high);
        QuickSort(r, low, pivotloc - 1); //对低子表进行递归排序
        QuickSort(r, pivotloc + 1, high);//对高子表进行递归排序
    }
}

/*第二种快排方法*/
int QuickSort_(int r[], int low, int high)
{
	if(low < high)
	{
		int pivotkey = r[low];//枢轴记录为r[low]
		int pl = low;
	    int ph = high;
	    
	    while (low < high) 
		{	
	        while (low < high && r[high] >= pivotkey) {
	            high--;
	        }//r[high] < pivotkey
	        
	        if(low < high)
	        	r[low++] = r[high];
	
	        while (low < high && r[low] <= pivotkey) {
	            low++;
	        }//r[low] > pivotkey
	        
	        if(low < high)
	        	r[high--] = r[low];
    	}//完成一次快排 
    	
		int pivotloc = low;//确定枢轴位置为low 
    	
		//重要!!!!!! 
    	r[pivotloc] = pivotkey; //一次快排结束之后 以low为分界线 r[low]处为上次快排的枢轴记录 
    	
		QuickSort_(r, pl, pivotloc - 1);//对低字表进行递归排序
		QuickSort_(r, pivotloc + 1, ph);//对高子表进行递归排序 
	}
}

//选择排序
void SelectSort(int r[])
{
	for(int i = 1; i < n; i++)// n-1趟 
	{
		int k = i;
		for(int j = i + 1; j <= n; j++)//选择出剩余元素中的最小值 
		{
			if(r[j] < r[k])
				k = j; 
		}
		if(k != i)//将第i个元素和剩余元素中的最小值交换 
		{
			Swap1(&r[k], &r[i]);
			//int t = r[i]; 
			//r[i] = r[k];
			//r[k] = t;
		}
	}
} 

/*合并子表*/ 
void Merge(int r[], int left, int mid, int right)
{
	//9个元素  left = 1; right = 9+1; mid = (1+9+1)/2 = 5;  10个元素 left = 1; right = 10; mid = 5; 
	int n1 = mid - left;//5 - 1 = 4 
	for(int i = 0; i < n1; i++)
	{
		L[i] = r[left + i]; //1 2 3 4 ... 
	} 
	int n2 = right - mid; //9+1 - 5 = 5
	for(int j = 0; j < n2; j++)
	{
		R[j] = r[mid + j];
	}
	L[n1] = inf;
	R[n2] = inf;//末尾元素初始化为无穷大
	
	int i = 0;//L[]元素指针
	int j = 0;//R[]元素指针 
	for(int k = left; k < right; k++)
	{
		if(L[i] <= R[j])
			r[k] = L[i++];
		else
			r[k] = R[j++];	
	} 
} 

/*归并排序*/
void MergeSort(int r[], int left, int right)
{
	if(left < right - 1)//right = n + 1 ; left = 1; 
	{
		//下标是1开始所以需要right = n + 1,这样分成左右子表时的元素下标才正确 
		int mid = (left + right) / 2; 
		MergeSort(r, left, mid);//对左子表进行递归合并排序 
		MergeSort(r, mid, right);//对右子表进行递归合并排序 
		Merge(r, left, mid, right);//合并 左右子表 
	}
}

/*
调整为大顶堆
子节点下标需要注意:
1. 若是待排序序列下标是1开始的 
	则父节点的下标是<序列长度/2 = j>,
		左孩子结点的下标是<2*j>,
		右孩子结点的下标是<2*j+1>
2. 若是待排序序列下标是1开始的 
	则父节点的下标是<序列长度/2-1 = j>, 
		左孩子结点的下标是<2*j+1>,
		右孩子结点的下标是<2*j+2> 
*/
void HeapAdjust(int r[], int parent, int n)
{
	// 调整r[parent ... n]为大顶堆 parent是父节点  
	// n下标最大的子节点 也就是待排序序列的长度 
	// 其实调整的值为 以parent为根节点的二叉树 满足大/小顶堆的定义 
	int temp = r[parent];//父节点的值暂存 
	
	for(int j = 2 * parent; j <= n; j++)
	{
		//右孩子是最大的结点 否则 左孩子是最大的节点 
		if(j < n && r[j] < r[j + 1])  ++j; 
		
		//父节点值>=右孩子结点值
		if(temp >= r[j]) break;
		
		//父节点值小于左/右孩子结点值
		r[parent] = r[j];//父节点值替换为左/右孩子结点值 
		parent = j;//parent暂存子节点下标 
	}
	//若break,父节点值无需右孩子结点交换值
	//否则,子节点的值替换为父节点的值 
	r[parent] = temp;	
} 

/*堆排序*/
void HeapSort(int r[])
{
	//从第一个非叶子结点n/2开始进行初始大顶堆构建 
	//元素个数为n个 下标从1开始的序列 非叶子节点下标为 n/2 ~ 1 
	for(int i = n / 2; i > 0; i--)
	{
		HeapAdjust(r, i, n); 
	} 
	
	for(int i = n; i > 1; i--)
	{
		//将大顶堆第一个值(最大)与最后一个值交换 
		//最后一个值变成最大的 第一个值变成堆顶元素 
		int t = r[1];
		r[1] = r[i];
		r[i] = t; 
		
		//此时还需要调整堆 将1~i-1调整为大顶堆 r[1]为整个堆的根节点 调整即可 
		HeapAdjust(r, 1, i - 1); 
	} 
}

void print(int r[])
{
    for (int i = 1; i <= n; i++)
    {
        cout << r[i] << " ";
    }
    cout << endl;
}

int main() {
    cin >> n;
    int r[maxn + 1];
    for (int i = 1; i <= n; i++)
        cin >> r[i];
    //插入排序
    //InsertSort(r);
    
    //折半插入排序
    //BiInsertSort(r);
    
	//希尔排序
    //int delta[3] = {3, 2, 1};
	//int t = 3;
    //ShellSort(r, delta, t);
    
	//冒泡排序
    //BubbleSort(r);
    
	//快速排序 2种不同的实现 
    //int low = 1;
    //int high = n;
    //QuickSort(r, low, high); 
    //QuickSort_(r, low, high);
    
	//选择排序
	//SelectSort(r);
	
	//归并排序
	//int left = 1;
	//int right = n + 1;
	//MergeSort(r, left, right); 
	
	//堆排序
	HeapSort(r); 
    print(r);

    return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值