数据结构-排序算法 c语言

191 阅读6分钟

笔记链接补充

数据结构学习
[blog.csdn.net/zbw328/arti…]

c 排序算法 [www.runoob.com/cprogrammin…]

c语言 二进制 负数

[blog.csdn.net/qq_16209077…] 正数的反码和补码都与原码相同。 负数的反码为对该数的原码除符号位外各位取反。 负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1

左移 << 丢弃最高位,低位补0 右移 >> 正数高位补0,负数高位补1 =》(对于正数其实就是做/2)

其他理解

希尔排序(分组插入排序)理解
[www.jianshu.com/p/d730ae586…]
将数组分成多个组,在每个组中进行(直接)插入排序:
分组间隔 = length/2 -> 1

快速排序
用三值中值方法区一个区间的基准值
小于基准值的放在左边 大于基准值的放在右边 (方式:初始i=0 j=last 将i左移j右移,直到arr[i] >= 基准 arr[j]<=基准停下,将ij交换;ij继续移动,直到ij交错,即i>j停止)
再将左右两边再排序,直到区间足够小
[zhuanlan.zhihu.com/p/57436476]

理解各种排序的动画及对应代码 [visualgo.net/en/sorting]

插入排序 insertion sort 稳定

以第一个元素为有序序列的初始,在剩下的未排序序列中依次选取元素插入有序序列
插入方式:从后向前扫描寻找合适位置插入,直到无序序列没有元素为止

void insertion_sort(int arr[] ,int ten){
	int i,j,temp;
	for(i = 1;i<len; i++){
		temp = arr[i];
		j = i-1;
		while(j>=0 && arr[j]>temp){
			arr[j+1] = arr[j]; //将有序序列中比temp大的元素往后移一位	
			j- -;
		}
		arr[j+1] = temp;
	}
}

希尔排序 shell sort

For gap => 分组排序,每一组进行插入排序
for i => 某一组内,要插进有序序列的值
for j => 某一组内,被即将插入的值比较的值(前部有序列表中的值)(从后向前)

void shell_sort(int arr[], int len){
	int i,j,gap,temp;
	for(gap = len >> 1; gap > 0; gap = gap>>1){ //右移等同于len/2
		for(i = gap; i<len; i++){
			temp = arr[i];
			for(j = i-gap; j>=0 && arr[j] > temp; j -= gap){
				arr[j+gap] = arr[j];
			}
			arr[j+gap] = temp;
		}
	}
}

冒泡排序 bubble sort

依次比较相邻元素把大的放到右边,i轮之后最大元素在末尾,下一轮比较前面n-i个
直至n-i=1,一共比较了n-1轮

Void bubble_sort(int arr[],int len){
	for(i=0;i<len-1;i++){
		for(j=0;j<len-1-i;j++){
			if(arr[j]>arr[j+1]){
				temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
}

选择排序 selection sort

每一轮在未排序序列中找出最小元素,放到有序序列(数组前部)的末尾

void selection_sort(int arr[],int len){
	int i,j,temp;
	for(i=0;i<len-1;i++){
		int min = i;
		for(j=i+1;j<len;j++){
			if(arr[j]<arr[min]){
				min = j
			}
		}
		temp = …..  //交换arr[i] 和 arr[min]
	}
}

归并排序 merge sort

分而治之的思想,类似二叉树(迭代或者递归)
分:将数组平分成两个子数组,子数组再平分成子数组,直到子数组只包含两个元素
治:将子数组从下到上各自排序再合并;合并时利用一个新的数组,将两个有序数组的元素依次比较按序填入

迭代方法

int min(int x, int y) {
    return x < y ? x : y;
}
void merge_sort(int arr[], int len) {
    int *a = arr; // a指针指向目标数组arr
    int *b = (int*) malloc(len * sizeof(int)); //直接分配一个最终合并所需长度的数组,b指针指向该数组
    int seg, start;
    for (seg = 1; seg < len; seg += seg) { 
        //seg为步长 2^x = len => x=log2n 
        for (start = 0; start < len; (start += seg) + seg) { 
	 //将子树两个一组(二叉树思想)依次比较合并
            int low = start, mid = min(start + seg, len), high = min(start + seg + seg, 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++];
        }
        // 修改指针指向 将该次合并的结果数组b与数组a交换
        int* temp = a;
        a = b;
        b = temp; //将a的换给b之后,下一轮b直接开始从0修改值(即废弃原a的值)
    }
    if (a != arr) { 
        // 指向arr的是b指针; 将排序的最终结果放回arr
        int i;
        for (i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
    free(b);
}

快速排序 quick sort

递归方法

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
/*使用快速排序的区间大小临界值,可根据实际情况选择*/
#define MAX_THRESH 4
typedef int ElementType;
/*元素交换*/
void swap(ElementType *a,ElementType *b)
{
    ElementType temp = *a;
    *a = *b;
    *b = temp;
}
/*插入排序*/
void insertSort(ElementType A[],int N)
{
    /*优化后的插入排序*/
    int j = 0;
    int p = 0;
    int temp = 0;
    for(p = 1;p<N;p++)
    {
        temp = A[p];
        for(j = p;j>0 && A[j-1] > temp;j--)
        {
            A[j] = A[j-1];
        }
        A[j] = temp;
    }

}
/*三数中值法选择基准*/
ElementType medianPivot(ElementType A[],int left,int right)
{
    int center = (left + right)/2 ;
    /*对三数进行排序*/
    if(A[left] > A[center])
        swap(&A[left],&A[center]);
    if(A[left] > A[right])
        swap(&A[left],&A[right]);
    if(A[center] > A[right])
        swap(&A[center],&A[right]);

    /*交换中值和倒数第二个元素*/    
    swap(&A[center],&A[right-1]);
    return A[right-1];
}

/*分区操作*/
int partition(ElementType A[],int left,int right)
{

    int i = left;
    int j = right-1;
    /*获取基准值*/
    ElementType pivot = medianPivot(A,left,right);
    for(;;)
    {
        /*i j分别向右和向左移动,为什么不直接先i++?*/
        while(A[++i] < pivot)
        {}
        while(A[--j] > pivot)
        {}

        if(i < j)
        {
            swap(&A[i],&A[j]);
        }
        /*交错时停止*/
        else
        {
            break;
        }

    }
    /*交换基准元素和i指向的元素*/
    swap(&A[i],&A[right-1]);
    return i;

}

void Qsort(ElementType A[],int left,int right)
{
    int i = 0;
    register ElementType *arr = A;
    if(right-left >= MAX_THRESH)
    {
        /*分割操作*/
        i = partition(arr,left,right);
        /*递归*/
        Qsort(arr,left,i-1);
        Qsort(arr,i+1,right);
    }
    else
    {
        /*数据量较小时,使用插入排序*/
        insertSort(arr+left,right-left+1);
    }
}
/*打印数组内容*/
void printArray(ElementType A[],int n)
{
    if(n > 100)
    {
        printf("too much,will not print\n");
        return;
    }
    int i = 0;
    while(i < n)
    {
        printf("%d ",A[i]);
        i++;
    }
    printf("\n");
}
int main(int argc,char *argv[])
{
    if(argc < 2)
    {
        printf("usage:qsort num\n");
        return -1;
    }
    int len = atoi(argv[1]);
    printf("sort for %d numbers\n",len);
    /*随机产生输入数量的数据*/
    int *A = malloc(sizeof(int)*len);
    int i = 0;
    srand(time(NULL));
    while(i < len)
    {
       A[i] = rand();
       i++;
    }
    printf("before sort:");
    printArray(A,len);
    /*对数据进行排序*/
    Qsort(A,0,len-1);
    printf("after  sort:");
    printArray(A,len);
    free(A);
    return 0;
}