1、冒泡排序
1)思想
设待排序元素序列中的元素个数为 n。最多作 n-1 趟,i = 1, 2, , n-1 。
在第 i 趟中从后(前)向前(后) ,j = n-1, n-2, , i,顺次两两比较V[j-1]和V[j]。如果发生逆序,则交换V[j-1]和V[j]。
第i趟对待排序元素序列V[i-1],V[i],,V[n-1]进行排序,结果将该序列中排序码最小(大)的元素交换到序列的第一个(最后)位置,其它元素也都向排序的最终位置移动。在个别情形,元素可能在排序中途向相反的方向移动。
2)自己的代码实现
public static void bubblesort(int[] arr)
{
int n=arr.length;
for(int i=0;i<n-1;i++)
{
for(int j=0;j<n-i-1;j++)
{
if(arr[j]>arr[j+1])
{
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
2、直接插入排序
1)思想
插入第i (i≥1) 个元素时,前面的V[0], V[1], …, V[i-1]已经排好序。这时,用V[i]的排序码与V[i-1], V[i-2], … 的排序码顺序进行比较,直到找到插入位置即将V[i]插入,原来位置上的元素向后顺移。
2)自己的代码实现
(最好画个图便于自己理解)
public static void insertsort(int[] arr)
{
int n=arr.length;
int i=0,j=0;
for(i=1;i<n;i++)
{
for(j=i-1;j>=0;--j)
{
if(arr[i]>arr[j])break;//j+1即arr[i]需插入的位置
}
int k=i,temp=arr[i];//要把arr[i]先保存下来
while(k>j+1)
{
arr[k]=arr[k-1];
k--;
}
arr[j+1]=temp;
}
}
3、快速排序
1)思想
2)自己的代码实现
递归:
public static void quicksort(int start,int end,int[] arr){
if(start>=end)return ;
int X=arr[start];
//如果要改成中间位置,只需把arr[mid]与arr[start]交换位置
int i=start,j=end;
while(i<j){
while(arr[j]>=X&&i<j)j--;
if(i<j)arr[i++]=arr[j];//填坑,j为新坑
while(arr[i]<X&&i<j)i++;
if(i<j)arr[j--]=arr[i];//填坑,i为新坑
}
arr[i]=X;
quicksort(start,i-1,arr);
quicksort(i+1,end,arr);
}
非递归:
public static void quicksort2(int start,int end,int[] arr){//非递归
Stack<Integer> s=new Stack<Integer>();
s.push(start);
s.push(end);
while(!s.empty()){
end=s.pop();
start=s.pop();
//partition
int X=arr[start];
int i=start,j=end;
while(i<j){
while(arr[j]>=X&&i<j)j--;
if(i<j)arr[i++]=arr[j];//填坑,j为新坑
while(arr[i]<X&&i<j)i++;
if(i<j)arr[j--]=arr[i];//填坑,i为新坑
}
arr[i]=X;
//以上为partition操作
int index=i;
if(start<index-1){
s.push(start);
s.push(index-1);//一定-1
}
if(end>index+1){
s.push(index+1);//一定+1
s.push(end);
}
}
}
4、归并排序
1)思想
将待排序的元素序列划分为两个长度大致相等的子序列;
分别对每个子序列递归排序;
最后将两个排好序的子序列合并成一个有序序列,即归并过程(称为两路归并(2-way merging))。
2)自己的代码实现
int[] temp;
public void merge(int[] nums,int start,int mid,int end){
int i=start,j=mid+1;
int index=start;
while(i<=mid&&j<=end){
if(nums[i]<=nums[j]){temp[index++]=nums[i];i++;}
else {temp[index++]=nums[j];j++;}
}
while(i<=mid){temp[index++]=nums[i];i++;}
while(j<=end){temp[index++]=nums[j];j++;}
for(i=start;i<=end;i++)nums[i]=temp[i];
}
public void mergeSort(int[] nums,int start,int end){
if(start>=end)return;
int mid=(start+end)/2;
mergeSort(nums,start,mid);
mergeSort(nums,mid+1,end);
merge(nums,start,mid,end);
}
5、堆排序
1)思想
2)自己的代码实现
public class TestHeap {
public static void main(String[] args) {
//PriorityQueue<Integer> pq=new PriorityQueue<Integer>((o1,o2)->o1-o2);
int[] arr= new int[]{1,3,4,2,6,8,5,7};
System.out.println("排序前:");
for(int i=0;i<arr.length;i++)System.out.print(arr[i]+",");
MyHeap h=new MyHeap(arr);
int[] res=new int[arr.length];
for(int i=0;i<arr.length;i++) {
res[i]=h.remove();
}
System.out.println("\n排序后:");
for(int i=0;i<arr.length;i++)System.out.print(res[i]+",");
}
}
class MyHeap{
private int[] data;
private int cursize;
public MyHeap(int[] data) {
this.data=new int[data.length];
System.arraycopy(data, 0, this.data, 0, data.length);
cursize=data.length;
int curIndex=(cursize-2)/2;//最后一个分支结点
//2*curIndex+2=cursize-1(cursize为奇数,最后一个结点为右结点)
//如cursize=3,curIndex=0
//2*curIndex+1=cursize-1(cursize为偶数,最后一个结点为左结点)
//如cursize=4,curIndex=1
while(curIndex>=0) {
siftDown(curIndex,cursize-1);
curIndex--;
}
}
public void siftDown(int start,int end) {
//如果子女的值小于父结点的值, 则关键码小的上浮,
//继续向下层比较, 将一个集合局部调整为最小堆。
int parentIndex=start,sonIndex=parentIndex*2+1;//为左结点
while(sonIndex<=end) {
if(sonIndex<end&&data[sonIndex]>data[sonIndex+1])sonIndex++;//让sonIndex指向两个子数中较小的
if(data[sonIndex]<data[parentIndex]) {
int temp=data[parentIndex];data[parentIndex]=data[sonIndex];data[sonIndex]=temp;
}
parentIndex=sonIndex;
sonIndex=parentIndex*2+1;
}
}
public int remove() {
int x=data[0];
data[0]=data[cursize-1];
cursize--;
siftDown(0, cursize-1);
return x;
}
}
6、希尔排序
1)思想
设待排序元素序列有 n 个元素,首先取一个整数 gap < n 作为间隔(增量),将全部元素分为 gap 个子序列,所有距离为 gap 的元素放在同一个子序列中,在每一个子序列中分别施行直接插入排序。
然后缩小间隔gap,例如取 gap = gap/2(取上界),重复上述的子序列划分和排序工作。直到最后取 gap = 1(此时序列“基本有序”),将所有元素放在同一个序列中排序为止
子序列插入排序
2)自己的代码实现
public static void shellSort(int start,int end,int[] arr){//希尔排序
int gap=arr.length/2;
int i=0,j=0;
while(gap>=1){//内部插入排序
for(int p=start;p<=end-gap;p++){
for(i=p+gap;i<arr.length;i+=gap)
{
for(j=i-gap;j>=0;j-=gap)
{
if(arr[i]>arr[j])break;//j+gap即arr[i]需插入的位置
}
int k=i,temp=arr[i];//要把arr[i]先保存下来
while(k>j+gap)
{
arr[k]=arr[k-gap];
k-=gap;
}
arr[j+gap]=temp;
}
}
gap=gap/2;
}
}
7、选择排序
1)思想
1)在元素 V[i]~V[n-1] 中选择具有最小排序码的元素;
2)若它不是这组元素中的第一个元素,则将它与这组元素中的第一个元素对调;
3)在这组元素中剔除这个具有最小排序码的元素,在剩下的元素V[i+1]~V[n-1]中重复执行第1)、2)步,直到剩余元素只有一个为止。
2)自己的代码实现
public static void selecrSort(int start,int end,int[] arr){
int minIndex=0;
for(int i=start;i<=end;i++){
minIndex=i;
for(int j=i+1;j<=end;j++){
if(arr[j]<arr[minIndex])minIndex=j;
}
if(minIndex!=i){
int temp=arr[i];
arr[i]=arr[minIndex];
arr[minIndex]=temp;
}
}
}
8、计数排序
1)思想
2)自己的代码实现
public static void jishu(int[] arr){
int max= Integer.MIN_VALUE,min=Integer.MAX_VALUE;
for(int i:arr){
if(i<min)min=i;
if(i>max)max=i;
}
int[] jishu=new int[max-min+1];
for(int i:arr){
jishu[i-min]++;
}
int index=0;
for(int i=0;i<jishu.length;i++){
while(jishu[i]-->0)arr[index++]=min+i;
}
}
9、桶排序
1)思想
2)自己的代码实现
public static void tong(int[] arr,int number){//number即每个桶中的平均数量
int max= Integer.MIN_VALUE,min=Integer.MAX_VALUE;
for(int i:arr){
if(i<min)min=i;
if(i>max)max=i;
}
int length=(max-min)/number+1;
ArrayList[] tong=new ArrayList[length];
for(int i=0;i<tong.length;i++){
tong[i]=new ArrayList<Integer>();
}
for(int i:arr){
tong[(i-min)/number].add(i);//加到相应的桶中去
}
int index=0;
for(int i=0;i<tong.length;i++){
Collections.sort(tong[i]);//桶内排序
for(int j=0;j<tong[i].size();j++)arr[index++]=(int) tong[i].get(j);
}
}
补充
1)时间复杂度:可以理解为代码执行的次数
比如二分法,一个长度为n的数组,用二分法查找,查找的次数就是时间复杂度
设次数为k,则2的k次方=n, k=log2 n(底数为2)
则时间复杂度为O(logn)
2)Arrays.sort()
较小用插入,较大用归并,其他用快排
3)稳定排序
稳定排序
题目
以下题目为大二上学期数据结构老师在PPT上放的思考题,答案为我自己的答案,不一定准确
1)如何对n个数进行排序,要求时间复杂度O(n),空间复杂度O(1)
答:计数排序
2)若有1T的数据,需要实现由大到小排序,你用什么办法,说说你的思路和想法?
答:每次读512M,内部排序,然后写到小文件里,之后再把这些小文件归并
3)若有10G的数据,如果两条数据一样,则表示该两条数据重复了,现在给你512M的内存,把这10G中重复次数最高的10条数据取出来。
答:
①先读进来第一个512M的数据,用hashmap记录每个数据重复的次数,
Map<Integer,Integer> map=HashMap<>();
if(map.containsKey(数据))map.put(数据,map.get(数据)+1);
else map.put(数据,1);
②然后读进来第二个,第一个中出现过的数据,就把它的次数+1,没出现过的写到一个temp.txt文件中
③重复第②步,依次把20个部分都读一遍,最后HashMap中存的就是20个部分中都出现过的数据,把它们桶排序,输出到result1.txt中
④之后再处理temp.txt中的数据
- 若它的大小小于等于 512M,则直接HashMap+桶排序,将结果输出到result2.txt里;
- 若它的大小大于512M,则继续分成多个部分,每次读512M,重复①②③,得到temp2.txt,temp3.txt等,以及result2.txt,result3.txt等
⑤如果有temp2.txt,temp3.txt之类的,重复第④步
⑥最后得到的result1.txt,result2.txt等,它们中的数据肯定是互相不重复的,且各自进行了桶排序,把重复次数最多的放在了最前面,所以接下来只需把每个文件中重复次数最多的前十个数据读进来,进行桶排序,即可得到所有数据中重复次数最多的十个数据