数据结构-排序(学习笔记)

  上课的时候老师就说排序很重要。最近又翻了翻《大话数据结构》和笔记,增强下记忆。

先说下几种排序的关系:

(盗个图)

1、冒泡排序:一种交换排序,基本思路是相邻的两两比较,反序则交换,直到没有反序为止。

void swap(int *p, int *q)
{
int temp = *p;
*p = *q;
*q = temp;
}


void bubble_sort(int a[], int len)           //冒泡
{
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j < len-i-1; j++)
{
if (a[j]>a[j+1])
swap(&a[j], &a[j+1]);
}
}
}

但如果是基本有序的数据,这样做效率就很低了,所以增加一个标记变量flag来实现冒泡的优化

void bubble_sort_plus(int a[], int len)        //冒泡优化
{
int c = 0;
for (int i = 0; i < len - 1; i++)
{
bool fiag = 1;//标记    
for (int j = 0; j < len - i - 1; j++)
{
if (a[j]>a[j + 1])     //相邻两元素比较
{
swap(&a[j], &a[j + 1]);
fiag = 0;//如果交换则标识符为0
}
}
if (fiag == 1)
break;
}
}

这样,排序的性能就有了一些提升,避免了无意义的循环判断。


2、选择排序:通过n-i次比较选出最小元素,并和第i个交换。

void select_sort(int a[], int len)           //选择排序
{
for (int i = 0; i < len; i++)
{
int min = i;        //假设第一个元素最小
for (int j = i + 1; j < len; j++)
{
if (a[j] < a[min])
min = j;    //判断   小于则记住下标
}
if (i != min)       //判断最小元素  
swap(&a[i], &a[min]);
}
}


3、直接插入:是将一个记录插入到已经排好的有序表中,得到一个新的有序表。

void insert_sort(int a[], int len)           //直接插入
{
for (int k = 1; k < len; k++)
{
int temp = a[k];//将要插入的值赋值给temp
int i = 0;
for (i = 0; i < k; i++)
{
if (a[i]>temp)  //比较找出要插入的位置
break;
}
for (int j = k - 1; j >= i; j--)

{
a[j + 1] = a[j]; //将元素向后移动 空出位置
a[i] = temp;         //插入元素
}
}

}

但是又有问题了,这么多循环太浪费时间了,所以可以在查找要插入的位置时一并将元素向后移动,空出位置

void insert_sort_plus(int a[], int len)         //直接插入优化
{
for (int k = 1; k < len; k++)
{
int temp = a[k];//将要插入的值赋值给temp
int i;
for (i = k - 1; i >= 0; i--)//从后向前判断
{
if (a[i]>temp)
a[i + 1] = a[i];//如果大于要插入的值则元素向后移动  空出位置
else
break;
}
a[i + 1] = temp;//赋值
}
}


4、希尔排序:

void shell_sort(int a[], int len)         //希尔排序
{
for (int i = len / 3 + 1; i > 0; i--)
shell_insert(a, len, i);
}


void shell_insert(int a[], int len, int gap)
{
for (int i = gap; i < len; i++)
{
int j;
if (a[i] < a[i - gap])
{
int temp = a[i];
for (int j = i - gap; j>0; j-=gap)
{
if (temp < a[j])
a[j + gap] = a[j];
}
a[j + gap] = temp;
}
}
}

定义一个增量,利用增量将序列分为一个个子序列,在子序列内进行直接插入排序。


5、堆排序:

             堆是具有  每个节点的值都大于(小于)或等于其左右孩子节点的值的大顶堆(小顶堆)性质的完全二叉树。

void heap_adjust(int a[], int start, int end)
{
int temp = a[start];
for (int i = 2 * start - 1; i < end; i++)
{
if (a[i] < a[i + 1] && i + 1 < end)
i++;              //让i等于左右子节点最大值下标
if (temp < a[i])
{
swap(&a[start], &a[i]);//若根节点小于最大子节点  交换
start = i;       // i作为根结点 循环继续
}
else
break;
}
}
void heap_sort(int a[], int len)              //堆排序
{
for (int i = len / 2 - 1; i >= 0; i--)
heap_adjust(a, i, len-1);  //从len/2-1处开始,调整为大顶堆
int end = len - 1;
while (end > 0)
{
swap(&a[0], &a[end]);//将最后一个元素与对顶元素交换
heap_adjust(a, 0, --end);//释放最后一个元素  调整剩下的元素
}
}


6、归并排序:假设初始序列有n个元素,将其看成n个子序列,两两归并,反复操作,直至得到长度为n的有序序列。

void merger(int a[], int start, int mid, int end)
{
int *b = (int *)malloc(sizeof(int)*(end - start + 1));
int low1 = start,low2=mid+1;
int high1 = mid,high2=end;
int i = 0;
while (low1 <= high1&&low2 <= high2)
{
if (a[low1] < a[low2])
b[i++] = a[low1++];
else
b[i++] = a[low2++];//比较 将两组元素按序拷到b中
}
while (low1 <= high1)
b[i++] = a[low1++];//low1未走完,将low1剩余元素拷到b中
while (low2 <= high2)
b[i++] = a[low2++];//low2未走完,将low2剩余元素拷到b中
i = 0;
for (int j = start; j <= end; j++)
a[j] = b[i++];      //将b中排好序的元素拷到a中
}


void mer_sort(int a[], int start, int end)
{
if (start < end)
{
int mid = (start + end) / 2;
mer_sort(a, start, mid);
mer_sort(a, mid + 1, end);//递归  
merger(a, start, mid, end);
}
}


void merger_sort(int a[], int len)       //归并    递归法
{
mer_sort(a, 0, len - 1);
}

// 

  非递归

void merger_loop(int a[], int len, int gap)                
{
int i = 0;
int *b = (int *)malloc(sizeof(int)*len);
int low1 = 0, high1 = low1 + gap - 1;
int low2 = high1 + 1, high2 = low2 + gap - 1 < len ? low2 + gap - 1 : len - 1;
while (low2 < len)        //low2没有超出数组长度
{
while (low1 <= high1&&low2 <= high2)
{
if (a[low1] < a[low2])
b[i++] = a[low1++];
else
b[i++] = a[low2++];//比较 将两组元素按序拷到b中
}
while (low1 <= high1)
b[i++] = a[low1++];//low1未走完,将low1剩余元素拷到b中
while (low2 <= high2)
b[i++] = a[low2++];//low2未走完,将low2剩余元素拷到b中
low1 = high2 + 1;
high1 = low1 + gap - 1;
low2 = high1 + 1;
high2 = low2 + gap - 1 < len ? low2 + gap - 1 : len - 1;
}
while (low1 < len)   //low2超出数组长度  low1没有超出
b[i++] = a[low1++];   //将low1剩余元素拷到b中
for (int j = 0; j < len; j++)
a[j] = b[j];
free(b);
}


void merger_sort_loop(int a[], int len)     //归并   非递归法
{
for (int i = 1; i < len; i *= 2)
merger_loop(a, len, i);//增量  比较的元素个数
}


7、快速排序:设定序列中的一个值为中间量,通过一趟排序将序列分为独立的两部分,一部分比中间量小,另一部分比中间量大,对这两部分继续排序。

void quick_sort(int a[], int len)           //快排   
{
quick(a, 0, len - 1);
}


void quick(int a[], int low, int high)
{
if (low < high)
{
int mid = partition(a, low, high);
quick(a, low, mid-1);
quick(a, mid +1, high);
}
}


int partition(int a[], int l, int r)
{
int temp = a[l];//将开始元素当作中间轴
while (l < r)
{
while (l < r&&a[r] >= temp)
r--;       
swap(&a[l], &a[r]);//从最后一位开始  若小于temp则交换位置 
                      //将小于temp得数放在前段  
while (l < r&&a[l] >= temp)
l++;
swap(&a[l], &a[r]);//从第一位开始  若大于temp则交换位置
                      //将大于temp得数放在后段
}
return l;//返回temp下标
}

//优化方案
//1,取出第一位,最后一位和中间为元素   取三者中间值
//2,将交换改为赋值   temp值不变
//3,当数据太小时  改用别的排序法


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值