考研数据结构--排序汇总(自用)

1、插入排序:

1)直接插入排序:
哨兵版:
void insertSort(int A[], int n)
{
	int i, j;
	for(i = 2; i <= n; i++)
	{
		A[0] = A[i];         //负责为哨兵,A[0]不存放元素 
		for(j = i - 1; A[0] < A[j]; j--)
			A[j+1] = A[j];
		A[j+1] = A[0];
	}
}
普通版:
void insertSort2(int A[], int n)
{
	int i, j;
	int temp; 
	for(i = 1; i < n; i++)
	{//A[0]放元素
		if(A[i] < A[i-1]) 
		{
			temp = A[i];   //暂存A[i];
			for(j = i-1; j >= 0 &&A[j] > temp; --j)
				A[j+1] = A[j];
			A[j+1] = temp;
		} 
	}
}
2)折半插入排序:在排好的序的部分折半查找插入位置
void insertSort3(int A[], int n)
{
	int i,j,low,high,mid;
	for(i = 2; i <= n; i++)
	{
		A[0] = A[i];
		low = 1; high = i - 1;
		while(low <= high)
		{
			mid = (low + high)/2;
			if(A[mid] > A[0]) high = mid - 1;
			else low = mid+1;
		}
		for(j = i-1; j >= low; --j)
		{//low指向要插入的位置low==high+1 
			A[j+1] = A[j];
		} 
		A[low] = A[0];
	}
}

在这里插入图片描述
在这里插入图片描述

2、希尔排序:

严版:

void shellInsert(int A[],int n,int dk)
{
	int i, j;
	for(i = 1+dk; i <= n; i++)
	{//对增量为dk的序列进行直接插入排序 
		if(A[i] < A[i-dk])
		{
			A[0] = A[i];     //暂存A[i]非哨兵,A[0]不存放元素;也可用temp代替 
			for(j = i-dk; j > 0 && A[0] > A[j]; j -= dk)
				A[j+dk] = A[j];
			A[j+dk] = A[0]; 
		}
	}
}

void shellSort(int A[], int n, int delta[], int t)
{//A为待排序列,n为其长度,delta为增量序列,t为其长度 
	for(int k = 0; k < t; k++)
	{//一个增量一趟 
		shellInsert(A, n, delta[k]);
	} 
}

在这里插入图片描述

3、冒泡排序:

void swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

void bubbleSort(int A[], int n)
{//升序,从后往前冒 
	for(int i = 0; i < n-1; i++)
	{
		bool flag = false;   //本趟是否发生过交换 
		for(int j=n-1; j > i; j--)
		{
			if(A[j] < A[j-1])
			{
				swap(A[j], A[j-1]);
				flag = true; 
			}
		}
		if(flag == false) //没有交换过,则已是升序 
			return ;
	}
}

在这里插入图片描述

4、快速排序:找到的所有版本,区别就是partition

1)初始版本:
#include<iostream>

using namespace std;
int partition(int A[],int low,int high)
{
	int pivotkey = A[low]; //选左边第一个pivotkey 
	int start = low; //暂存pivotkey的下标 
	while(low < high)
	{
		while(low < high && A[high] >= pivotkey) high--;
		while(low < high && A[low] <= pivotkey) low++;
		if(low < high)
		{
			swap(A[low],A[high]);
		} 
	}
	swap(A[low],A[start]);  //此时low == high,且A[low]必然是小于等于pivotkey的 
	return low;
} 
void QSort(int A[], int low, int high)
{
	if(low < high)
	{
		int pivotloc = partition(A, low, high);
		QSort(A, low, pivotloc-1);
		QSort(A, pivotloc+1, high);
	} 
} 
void QuickSort(int A[], int n)
{
	QSort(A,0,n-1);
}
int main()
{
	int A[10] = {4,2,1,4,5,6,7,8,9,3}; 
	QuickSort(A,10);
	for(int i = 0; i < 10; i++)
	{
		cout<<A[i]<<endl;
	}
	return 0; 
}
2)挖坑法:对上面的改进,严书上只有这个(但是暨大考过其他版本的,所以汇总下)
#include<iostream>
using namespace std; 
int partition(int A[],int low,int high)
{
	int pivotkey = A[low];
	while(low < high)
	{
		while(low < high && A[high] >= pivotkey) high--;
		A[low] = A[high];
		while(low < high && A[low] <= pivotkey) low++;
		A[high] = A[low];
	}
	A[low] = pivotkey;
	return low;
} 

3)前后指针法:
最右边的枢纽:
int partition(int A[],int low,int high)
{
	int pivotkey = A[high]; //最右边为枢纽
	int i = low - 1;
	for(int j = low; j <= high-1; j++)
	{
		if(A[j] < pivotkey)
		{
			i++;
			swap(A[i], A[j]); 
		}
	} 
	swap(A[i+1],A[high]);   //[low,i]、i+1、[i+2,high] 
	return i+1; 
}
最左边的为枢纽:
int partition(int A[],int low,int high)
{
	int pivotkey = A[low]; //最左边为枢纽
	int i = high+1;
	for(int j = high; j > 0; j--)
	{
		if(A[j] > pivotkey)
		{
			i--;
			swap(A[i], A[j]); 
		}
	} 
	swap(A[i-1],A[low]);   //[low,i]、i+1、[i+2,high] 
	return i-1; 
}
王道这样写的,感觉好点
int partition(int A[],int low,int high)
{
	int pivotkey = A[low]; //最左边为枢纽
	int i = low;
	for(int j = low+1; j <= high; j++)
	{
		if(A[j] < pivotkey)
		{
			swap(A[++i], A[j]); 
		}
	} 
	swap(A[i],A[low]);
	return i; 
}
随机位置:
int partition(int A[], int low,int high)
{
	int random_index = rand()%(high-low+1);
	swap(A[low],A[random_index]);
	int pivotkey = A[low];
	while(low < high)
	{
		while(low < high && A[high] >= pivotkey)high--;
		A[low] = A[high]; 
		while(low < high && A[low] <= pivotkey) low++;
		A[high] = A[low];
	} 
	A[low] = pivotkey;
	return low;
}
int partition(int A[], int low, int high)
{
	int random_index = rand()%(high-low+1);
	swap(A[low],A[random_index]);
	int pivotkey = A[low];
	int i = low;
	for(int j = low+1;j <= high; j++)
	{
		if(A[j] < pivotkey)
		{
			swap(A[++i],A[j]);
		}
	}
	swap(A[i],A[low]);
	return i;
}
暨大考题2020:填空
int partition(int* A, int N, int p, int r)
{	  int x = A[r];
      int i =   //(5)   ;
       for (int j = p; j<=r-1; j++){
          if (   //(6)   ){
              i = i + 1;
              int temp = A[i];
			A[i] = A[j];
			A[j] = temp;
		 }
	   }
	   int temp = A[i+1];
        A[i+1] = A[r];
        A[r] = temp;
	   return   //(7)  ;
}
void QuickSort(int* A, int N, int p, int r)
{
	 int q;
	 if (   //(8)  ){
		q = partition(A, N, p, r);
		QuickSort(    //(9)    );
		QuickSort(    //(10)   );
	  }
	  return;
}
void main()
{	  QuickSort(A, N, 0,N-1);
      return 0;
}
4)Hoare分区方案:第1个版本的另一种写法
int partition(int arr[],int low, int hight)
{
	int pivot = arr[low];	
	int i = low - 1;
	int j = hight + 1; 
	while(true)
	{
		while(arr[++i] < pivot);		//找 >= pivot的 
		while(arr[--j] > pivot);		//找 <= piovt的
		if(i >= j)
		{
			return j;
		}	
		swap(arr[i],arr[j]);
	}
}
5)非递归版本:分区用哪个版本无所谓
#include<iostream>
#include<stack>
 
using namespace std;

int partition(int A[],int low,int high)
{
	int pivotkey = A[low];
	while(low < high)
	{
		while(low < high && A[high] >= pivotkey) high--;
		A[low] = A[high];
		while(low < high && A[low] <= pivotkey) low++;
		A[high] = A[low];
	}
	A[low] = pivotkey;
	return low;
} 
void QSort(int A[], int low, int high)
{
	stack<int>stk;
	if(low < high)
	{
		stk.push(low);  //先左后右进栈,先右后左出栈 
		stk.push(high);
		while(!stk.empty())
		{
			int right = stk.top(); stk.pop();
			int left = stk.top(); stk.pop();
			int pivotloc = partition(A,left, right);  //枢纽下标 
			if(left < pivotloc - 1)
			{//左边还有两个及以上的元素 
				stk.push(left); 
				stk.push(pivotloc-1);
			}
			if(right > pivotloc + 1)
			{//左边还有两个及以上的元素 
				stk.push(pivotloc+1);
				stk.push(right);	
			}
		}
	}
} 
void QuickSort(int A[], int n)
{
	QSort(A,0,n-1);
}
int main()
{
	int A[10] = {4,2,1,4,5,6,7,8,9,3}; 
	QuickSort(A,10);
	for(int i = 0; i < 10; i++)
	{
		cout<<A[i]<<endl;
	}
	return 0; 
}
队列版:
void QSort(int A[], int low, int high)
{
	queue<int>q;
	if(low < high)
	{
		q.push(low);  
		q.push(high);
		while(!q.empty())
		{
			int left = q.front(); q.pop();
			int right = q.front(); q.pop();
			int pivotloc = partition(A,left, right);  //枢纽下标 
			if(left < pivotloc - 1)
			{//左边还有两个及以上的元素 
				q.push(left); 
				q.push(pivotloc-1);
			}
			if(right > pivotloc + 1)
			{//左边还有两个及以上的元素 
				q.push(pivotloc+1);
				q.push(right);	
			}
		}
	}
}

在这里插入图片描述

快排扩展:第k小的数
int kth_elem(int A[],int low, int high, int k)
{
	int pivot = A[low];
	int left = low;
	int right = high;
	while(left < right)
	{
		while(left < right && A[right] >= pivot) right--;
		A[left] = A[right];
		while(left < right && A[left] <= pivot) left++;
		A[right] = A[left];
	}
	A[left] = pivot;  //left == right
	//上面和快排分区没什么不同
	if(left == k)
	{
		return A[left];
	}
	else if(left > k)
	{
		return kth_elem(A, low, left-1, k);
	} 
	else
	{
		return kth_elem(A, left+1, high, k);	
	}
} 

5、堆排序:

顺序存储的完全二叉树下标
  • 0开始时,n个结点,最大分支结点编号是((n-1)-1)/2,双亲编号是(i-1)/2,都是向下取整.
  • 1开始时,n个结点,最大分支结点编号是n/2,双亲编号是i/2,都是向下取整。
基于大根堆:下标从1开始
void HeapAdjust(int A[], int k, int len)
{//自顶向下调整siftDown
	A[0] = A[k];
	for(int i = 2*k; i < len; i*=2)
	{
		if(i < len && A[i] < A[i+1])
		{
			i++;  //取较大的子女下标 
		}
		if(A[0] >= A[i]) break;
		A[k] = A[i];
		k = i;
	} 
	A[k] = A[0];
}
void BuildMaxHeap(int A[], int len)
{//建堆   
	for(int i = len/2; i > 0; i--)
	{//len/2是编号最大的分支结点 
		HeapAdjust(A, i, len);
	}
} 
void HeapSort(int A[], int len)
{
	BuildMaxHeap(A,len);   //建立初始大根堆
	for(int i = len; i > 1; i--)
	{
		swap(A[i], A[1]);   //输出堆顶元素(输出到堆底) 
		HeapAdjust(A, 1, i-1); //调整,把剩下的i-1个元素组成堆 
	} 
} 
小根堆:下标从0开始(多写了,加了插入和删除,如果只是用小根堆来排序不用写这么麻烦)
const int heapSize = 50;
typedef int HElemType;
typedef struct {
	HElemType elem[heapSize]; 
	int curSize;
}minHeap;

void siftDown(minHeap &heap, int i, int n)
{
	HElemType cur = heap.elem[i]; //i是双亲,j是i的值更小的子女 
	for(int j = 2*i+1; j < n; j = 2*j +1)
	{
		if(j < n-1 && heap.elem[j] > heap.elem[j+1]) j++;   //有右兄弟,且右兄弟更小
		if(cur <= heap.elem[j]) break; //双亲比子女更小,停止向下 
		else{
			heap.elem[i] = heap.elem[j]; //双亲比子女 
			i = j;
		} 
	}	
	heap[i] = cur;
}
viod siftUp(minHeap &heap, int start)
{//自底向下调整小根堆
	 HElemType cur = heap.elem[start];
	 int j = start; //j是子女
	 int i = (j-1)/2;  //i是j的双亲 
	 while(j > 0)
	 {
	 	if(heap.elem[i] <= cur) break;     //双亲更小停止向上
		else{
			heap.elem[j] = heap.elem[i]; //双亲比子女大,让子女上去(把双亲拉下来) 
			j = i;          //上一层 
			i = (i-1)/2;   //上一层 
		} 
	 } 
	 heap.elem[j] = cur;
}
void insert(minHeap &heap, int x)
{
	if(heap.curSize == heapSize) return false;
	heap.elem[heap.curSize] = x;
	siftUp(heap,heap.curSize);
	heap.curSize++; return true;
}
void delete(minHeap &heap, int &x)
{//删除堆顶元素,并赋值给x
	if(heap.curSize == 0) return false;
	x = heap.elem[0]; 
	heap.elem[0] = heap.elem[--heap.curSize];
	siftDown(heap, 0, heap.curSize);
	return true;	
} 
void creatMinHeap(minHeap &heap, ElemType arr[], int n)
{//创建小根堆 
	for(int i = 0; i < n; i++) heap.elem[i] = arr[i];
	heap.curSize = n;
	for(int i = (n-2)/2; i >= 0; i--)
	{
		siftDown(heap, i, heap.curSize);
	}
} 
HElemType* heapSort(minHeap heap) 
{
	HElemType *res = new HElemType[heap.curSize];
	int j = 0;
	for(int i = heap.curSize-1; i >= 0; i--)
	{
		res[j++] = heap.elem[0];
		swap(heap.elem[i],heap.elem[0]);
		siftDown(heap, 0, i); 
	} //heap不是小根堆了 
	return res;
}
判断是不是小根堆:
bool isMinHeap(int A[], int len)
{
	if(len%2 == 0) //len为偶数有一个单分支结点且是编号最大的分支结点 
	{
		if(A[(len-2)/2] > A[len-1])
		{
			return false; 
		}
		for(int i = (len-2)/2-1; i >= 0; i--)
		{
			if(A[i] > A[2*i+1] || A[i] > A[2*i+2])
			{
				return false;
			}
		}
	} 
	else
	{
		for(int i = (len-2)/2; i >= 0; i--)
		{
			if(A[i] > A[2*i+1] || A[i] > A[2*i+2])
			{
				return false;
			}
		}
	}
} 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6、归并排序:

以前写的:归并排序
在这里插入图片描述

迭代版本:
void MergeSort(int arr[],int len)
{
	int *a = arr;
	int *b = new int[len];   //辅助数组 
	for(int seg=1; seg < len; seg += seg)
	{
		for(int start = 0; start < len; start += seg*2)
		{
			int low = start, mid = min(start+seg, len), high = min(start+seg*2,len);
			int k = low;
			int start1 = low, end1 = mid;
			int start2 = mid, end2 = high;
			while(start1 < end1 && start2 < end2)
				b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
			while(start1 < end1) 
				b[k++] = a[start1++];
			while(start2 < end2)
				b[k++] = a[start2++];
		}
		int *temp = a;   //交换a和b的指向,让b下一轮还是指向辅助数组 
		a = b;			//交换会让arr和辅助数组的地位在下一轮中互换 
		b = temp;		//而每轮循环结束后,a都指向本轮归并结果数组 
	}
	//结束上面语句后a指向的是排序后的数组,但因为arr和一开始的辅助数组角色互换
	//所以,如果 a != arr就说明最后一轮arr是被当作辅助数组用的
	//注:arr的指向是不会变的 
	if(a != arr)
	{
		for(int i = 0; i < len; i++)
		{
			b[i] = a[i]; //或者写成arr[i] = a[i];
		} 
		b = a; 
	} 
	delete [] b;
} 
递归版本:

void Merge(int A[], int temp[], int low, int mid, int high)
{
	for(int k = low; k <= high; k++)
	{
		temp[k] = A[k];
	}
	for(int i = low, j= mid + 1, k = i;i <= mid&&j <=high; k++)
	{
		if(temp[i] <= temp[j])  A[k] = B[i++];
		else A[k] = B[j++]; 
	} 
	while(i <= mid) A[k++] = temp[i++];
	while(j <= high) A[k++] = temp[j++];
} 
void MSort(int A[],int temp[],int low,int high)
{
	if(low < high)
	{
		int mid = (high - mid)/2;
		MSort(A, temp, low, mid);
		MSort(A, temp, mid+1, high);
		Merge(A, temp, low, mid, high);
	}
}
void MergeSort(int A[], int low, int high, int n)
{
	int *temp = new int[n];
	MSort(A, temp, low, high);
}

在这里插入图片描述

7、基数排序:

基数排序分两种:最高位优先MSD(Most Significant Digit first)和最低位优先LSD(Least Significant Digit first),MSD应该不考,以后再看,下面代码基于LSD.
#include<iostream>
#include<queue>

using namespace std;

int power(int di)
{
	int res = 1;
	for(int i = 0; i < di; i++) res *= 10;
	return res;
}
void print(int A[],int len)
{
	for(int i = 0; i < len; i++)
	{
		cout<<A[i]<<"  ";
	} 
	cout<<endl;
}
void RadixSort(int A[], int len, int d)
{
	//print(A,len);
	queue<int>qarr[10];
	for(int i = 0; i < d; i++)
	{
		//分配 
		int pow = power(i);
		for(int j = 0; j < len; j++){ 
			int index = A[j]/pow% 10;
			qarr[index].push(A[j]); 
		}
		//收集,按qarr[0]、qarr[1].....收集结果为升序,反之为降序
		int k = 0;
		for(int j = 0; j < 10; j++)  
		{
			while(!qarr[j].empty())
			{
				int cur = qarr[j].front(); qarr[j].pop();
				A[k++] = cur;
			}
		}
	} 
	//print(A,len);
} 
int main()
{
	int A[10] = {105,12, 3, 45,47, 31, 5,6,9,567};
	RadixSort(A,10,3);
	return 0;
}
注:上面代码不能处理负数情况,负数应该也不考

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
可以参考

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值