数据结构中的排序算法。

排序算法的相关知识:

(1)排序的概念:所谓排序就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来。

(2)稳定的排序方法:在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的。相反,如果发生改变,这种排序方法不稳定。

(3)排序算法的分类(分为5类):插入排序、选择排序、交换排序、归并排序和分配排序。

(4)排序算法两个基本操作:<1>比较关键字的大小。

<2>改变指向记录的指针或移动记录本身。

具体的排序方法:

插入排序

<1>插入排序(Insertion Sort)的思想:每次将一个待排序的记录按其关键字大小插入到前面已经排好序的子记录中的适当位置,直到全部记录插入完成为止。

<2>常用的插入排序方法有直接插入排序和希尔排序。

(1)直接插入排序

<1>算法思路:把一个记录集(如一个数组)分成两部分,前半部分是有序区,后半部分是无序区;有序区一开始有一个元素r[0],无序区一开始是从r[1]到之后的所有元素;然后每次从无序区按顺序取一个元素r[i],拿到有序区中由后往前进行比较,每次比较时,有序区中比r[i]大的元素就往后移动一位,直到找到小于r[i]的元素,这时r[i]插到小元素的后面,则完成一趟直接插入排序。如此反复,从无序区不断取元素插入到有序区,直到无序区为空,则插入算法结束。

<2>算法演示:

//直接插入排序:#include<iostream> using namespace std;
void InsertSort(int r[],int n);
int main() { int r[]={24,1,56,2,14,58,15,89}; InsertSort(r,8); for(int i=0;i<8;i++) { cout<<r[i]<<'\t'; } cout<<endl; return 0; }
void InsertSort(int r[],int n) { for(int i=1;i<n;i++) { for(int j=i-1,s=r[i];s<r[j] && j>=0;j--) { r[j+1]=r[j]; } r[j+1]=s; } }

(2)折半插入排序

<1>算法思路:我们看到在直接插入排序算法中,需要在有序区查找比r[i]的小的元素,然后插入到这个元素后面,但这里要注意这个元素是从无序区算第一个比r[i]小的元素。折半插入排序就是在有序区折半查找这个元素。

<2>算法演示:

//折半插入排序#include<iostream> using namespace std;
void BinInsertSort(int r[],int n);
int main() { int r[]={53,34,76,23,55,28,63,88,34,66}; BinInsertSort(r,10); for(int i=0;i<10;i++) { cout<<r[i]<<"\t"; } cout<<endl; return 0; }
void BinInsertSort(int r[],int n) { for(int i=1;i<n;i++) { int s=r[i]; int low=0; int high=i-1; while(low <= high) { int mid=(low+high)/2; if(s < r[mid]) { high=mid-1; } else { low=mid+1; } } for(int j=i-1;j>=high+1;j--) { r[j+1]=r[j]; } r[high+1]=s; //r[high+1]是要找的元素 } }

(3)希尔排序(Shell Sort)

<1>算法思路:把整个记录近一个步长step(一般取记录长度的1/2),分成step个组,再分别对每个级进行直接插入排序;然后再把整个记录近一个新的步长(一般取step/2)分成step/2个组,再分别对每个组进行直接插入排序;如此不断的缩小步长,反复分组排序,直到步长等于1为此(步长为1则不可能再分组,1是元素之间距离的最小值)。可以看出,希尔排序实质是一种分组插入方法。

<2>算法演示:

//希尔排序:#include<iostream> using namespace std;
void ShellSort(int r[],int n); int main() { int r[]={24,1,56,2,14,58,15,89}; ShellSort(r,8); for(int i=0;i<8;i++) { cout<<r[i]<<'\t'; } cout<<endl; return 0; }
void ShellSort(int r[],int n) { int step=n/2; while(step >= 1) { for(int i=step;i<n;i+=step) { for(int j=i-step,s=r[i];s<r[j] && j>=0;j-=step) { r[j+step]=r[j]; } r[j+step]=s; } step/=2; } }

选择排序

<1>选择排序的思想:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已经排好的记录最后,直到全部记录排序完毕。

<2>常用的选择排序方法有直接选择排序和堆排序。

(1)直接选择排序

<1>算法思路:把待排序的n个元素看成一个有序区和一个无序区,开始的时候有序区为空,无序区包含了全部n个元素。排序的时候,每次从无序区中选择比较出其中最小一个元素放到有序区中。如此反复操作,无序区中每小一个元素,有序区中就多一个元素,直到无序区的所有元素都转到有序区中。

<2>算法演示:

//简单选择排序:#include<iostream> using namespace std;
void SelectSort(int r[],int n);
int main() { int r[]={53,34,76,23,55,28,63,88,34,66}; SelectSort(r,10); for(int i=0;i<10;i++) { cout<<r[i]<<"\t"; } cout<<endl; return 0; }
void SelectSort(int r[],int n) { for(int i=0;i<n-1;i++) { int small_loc=i; for(int j=i+1;j<n;j++) { if(r[small_loc] > r[j]) { small_loc=j; } } if(small_loc != i) { int temp=r[i]; r[i]=r[small_loc]; r[small_loc]=temp; } } }

(2)堆排序

<1>算法思路:大根堆二叉树中的非终端结点的元素值均大于它的左右孩子的值,因此知道堆的最大值是它的根结点。当根结点移出,则重新调整堆后,堆的次大值称为根结点,依次操作,可以得到堆的从大到小的有序序列。这个算法过程就是堆排序。

堆排序有一个建堆、筛选堆、调整堆的过程。

<2>算法演示:

//堆排序:#include<iostream> using namespace std;
void HeapAdjust(int r[],int i,int j); void HeapSort(int r[],int n);
int main() { int r[]={53,34,76,23,55,28,63,88,34,66}; HeapSort(r,10); for(int i=0;i<10;i++) { cout<<r[i]<<"\t"; } cout<<endl; return 0; }
void HeapAdjust(int r[],int i,int j) //调整堆{ int child=2*i; int temp=r[i]; //temp临时存放根结点 while(child <= j) //沿大儿子向下调整 { if(child<j && r[child+1]>r[child]) child++; if(temp >= r[child]) break; r[child/2]=r[child]; child=2*child; } r[child/2]=temp; }
void HeapSort(int r[],int n) //建堆{ for(int i=(n-1)/2;i>=0;--i) { HeapAdjust(r,i,n-1); //初始建堆 } for(i=n-1;i>0;--i) { //将当前堆顶元素与当前堆尾元素互换 int temp=r[0]; r[0]=r[i]; r[i]=temp; HeapAdjust(r,0,i-1); //将剩下的元素重新调整成堆 } }

交换排序

<1>交换排序的思想:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。

<2>常用的交换排序方法有冒泡排序和快速排序。

(1)冒泡排序

<1>算法思路:通过相邻元素的值的大小比较,并交换值较大的(较小的)元素,使得元素从一端移到到另一端,就像水底冒出的气泡一样。

<2>算法演示:

//起泡法排序:#include<iostream> using namespace std; #define N 5   //N为数的总个数
void BubbleSort(int r[],int n);
int main() { int i; int a[N]; cout<<"请输入"<<N<<"个数字:"; for(i=0;i<N;i++) { cin>>a[i]; } BubbleSort(a,N); for(i=0;i<N;i++) { cout<<a[i]<<"\t"; } cout<<endl; return 0; }
void BubbleSort(int r[],int n) { for(int i=0;i<n-1;i++) //进行n-1次循环,实现n-1趟比较 { for(int j=0;j<n-1-i;j++) //在每一趟中进行n-1-i次比较 { if(r[j]>r[j+1]) { int temp=r[j]; r[j]=r[j+1]; r[j+1]=temp; } } } }

(2)快速排序

<1>算法思路:通过一趟排序将准备排序的元素集合分成两个部分,其中一部分的元素的值都小于另一部分,然后对这两部分的元素集合内部再分别重复进行上面的排序过程,直到所有的元素都排列有序。

<2>算法演示:

//快速排序:#include<iostream> using namespace std;
int Partition(int r[],int low,int high); void QuickSort(int r[],int low,int high);
int main() { int r[]={53,34,76,23,55,28,63,88,34,66}; QuickSort(r,0,10-1); for(int i=0;i<10;i++) { cout<<r[i]<<"\t"; } cout<<endl; return 0; }
int Partition(int r[],int low,int high) { int pivotkey=r[low]; int i=low; int j=high; while(i<j) { while(i<j && r[j]>pivotkey) j--; if(i<j){r[i]=r[j];i++;} while(i<j && r[i]<pivotkey) i++; if(i<j){r[j]=r[i];j--;} } r[j]=pivotkey; return j; }
void QuickSort(int r[],int low,int high) { if(low<high) { int pivot=Partition(r,low,high); QuickSort(r,low,pivot-1); QuickSort(r,pivot+1,high); } }

归并排序

<1>归并排序的思想:假设数组r有n个元素,那么可以看成数组r是由n个有序的子序列组成,每个子序列的长度为1,然后再两合并,得到了一个长度是2(或1)的有序子序列,再两两合并,如此重复,直到得到一个长度为n的有序数据序列为止,这种排序方法称为二路归并排序。

<2>常用的交换排序方法有二路归并排序和三路归并排序。

(1)二路归并排序

<1>算法思路:如上。

<2>算法演示:

//二路归并排序#include <iostream> using namespace std; int *a=new int[20]; int n=0;
//归并排序,排序结果放到了b[]中void Merge(int a[],int b[],int left ,int mid,int right)//此处的right指向数组中左后一个元素的位置{ int i=left; int j=mid+1; int k=left; while(i<=mid && j<=right) { if(a[i]<=a[j])b[k++]=a[i++]; else b[k++]=a[j++]; } while(i<=mid) b[k++]=a[i++]; while(j<=right) b[k++]=a[j++]; }
//从b[]中又搬到了a[]中void Copy(int a[],int b[],int left,int right)//right同上{ for(int i=left;i<=right;i++) a[i]=b[i]; }
//划分并排序void MergeSort(int a[],int left,int right)//同上{ int *b = new int[right-left+1]; if(left<right) { //将当前传经来的数组划分成更小的大小几乎相同的数组 int i=(left+right)/2; MergeSort(a,left,i); MergeSort(a,i+1,right); //将小数组合成大数组,同时排序,结果放到b[]中 Merge(a,b,left,i,right); //从b[]中挪到a[]中 Copy(a,b,left,right); } }
void Input() { cout<<"Please Input array's size:"; cin>>n; cout<<"Array's elemants:"<<endl; for(int i=0;i<n;i++) cin>>a[i]; //调用算法 MergeSort(a,0,n-1); }
void Output() { for(int i=0;i<n;i++) cout<<a[i]<<" "; cout<<endl; }
int main() { Input(); Output(); return 0; }

C/C++ 数据结构之算法(面试)的更多相关文章

  1. 面试常考的常用数据结构与算法(zz)

    数据结构与算法,这个部分的内容其实是十分的庞大,要想都覆盖到不太容易.在校学习阶段我们可能需要对每种结构,每种算法都学习,但是找工作笔试或者面试的时候,要在很短的时间内考察一个人这方面的能力,把每种结 ...

  2. 大公司面试经典数据结构与算法题C#/Java解答

    几个大公司(IBM.MicroSoft and so on)面试经典数据结构与算法题C#解答 1.链表反转 我想到了两种比较简单的方法 第一种是需要开一个新的链表,将原链表的元素从后到前的插入到新链表 ...

  3. 数据结构+算法面试100题~~~摘自CSDN

    数据结构+算法面试100题~~~摘自CSDN,作者July 1.把二元查找树转变成排序的双向链表(树) 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调 ...

  4. C++程序员面试题目总结(涉及C++基础、多线程多进程、网络编程、数据结构与算法)

     说明:C++程序员面试题目总结(涉及C++基础知识.多线程多进程.TCP/IP网络编程.Linux操作.数据结构与算法) 内容来自作者看过的帖子或者看过的文章,个人整理自互联网,如有侵权,请联系作者 ...

  5. 数据结构与算法-江西师范大学865(针对考研or面试)

    可以加我微信chenyoudea免费要江西师范大学865资料全套pdf 目录 第一篇 数据结构与算法(针对考研or面试) 第二篇 真题演练 第三篇 复试 第四篇 推荐阅读 第一篇 数据结构与算法(针对 ...

  6. php面试之数据结构和算法

    二.数据结构和算法 1.使对象可以像数组一样进行foreach循环,要求属性必须是私有.(Iterator模式的PHP5实现,写一类实现Iterator接口)(腾讯) <?php class T ...

  7. 数据结构与算法JavaScript (一) 栈

    序 数据结构与算法JavaScript这本书算是讲解得比较浅显的,优点就是用javascript语言把常用的数据结构给描述了下,书中很多例子来源于常见的一些面试题目,算是与时俱进,业余看了下就顺便记录 ...

  8. 翻阅《数据结构与算法javascript描述》--数组篇

    导读: 这篇文章比较长,介绍了数组常见的操作方法以及一些注意事项,最后还有几道经典的练习题(面试题). 数组的定义: JavaScript 中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性 ...

  9. 数据结构与算法javascript描述

    <数据结构与算法javascript描述>--数组篇 导读: 这篇文章比较长,介绍了数组常见的操作方法以及一些注意事项,最后还有几道经典的练习题(面试题). 数组的定义: JavaScri ...

  10. Python 数据结构和算法

    阅读目录 什么是算法 算法效率衡量 算法分析 常见时间复杂度 Python内置类型性能分析 数据结构 顺序表 链表 栈 队列 双端队列 排序与搜索 冒泡排序 选择排序 插入排序 希尔排序 快速排序 归 ...

随机推荐

  1. 30款免费的手机UI设计资源

    在 原型设计阶段,我们会尽量寻找一些灵感刺激大脑,从而让我们的想象力飞-灵感给了我们很好的开始,但是当我们把灵感化为现实的时候,又需要一些实用而又高 效的组件来完成.即使你有非常善于把灵感实例化在草稿 ...

  2. Closing a window

    The obvious way to how to close a window is to click on the x mark on the titlebar. In the next exam ...

  3. ios上线流程

    一.前言: 作为一名iOSer,把开发出来的App上传到App Store是必要的.下面就来详细讲解一下具体流程步骤. 二.准备: 一个已付费的开发者账号(账号类型分为个人(Individual).公 ...

  4. winform网络编程之TcpClient类,TcpListener类和UdpClient类

    TcpClient类和TcpListener类 (1)TcpClient的用途: 用于在同步阻止模式下通过网络来链接.发送和接受流数据,在此情况下,必须有侦听此连接的请求,而侦听的任务就交给TcpLi ...

  5. 〖Windows〗zigbee实验之cygwin编译TestSimpleMac出错的解决方法

    1. 错误代码如下: ... C51 COMPILER V8. - SN: K1CMC-IEYCYC COPYRIGHT KEIL ELEKTRONIK GmbH - *** ERROR C141 I ...

  6. python之poplib模块下载并解析邮件

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #python之poplib模块下载并解析邮件 #https://github.com/michaelliao ...

  7. sql优化经历(转存+记录)

    sql优化经历 补充:看到这么多朋友对sql优化感兴趣,我又重新补充了下文章的内容,将更多关于sql优化的知识分享出来, 喜欢这篇文章的朋友给个赞吧,哈哈,欢迎交流,共同进步. 2015-4-30补充 ...

  8. Centos定时执行python脚本

    其实就是linux的定时任务.老记不住参数,这次写下来,省着老百度.本文没有技术含量,请大家不要吐槽. ================================================ ...

  9. mysql sleep连接太多怎么办

    摘要:interactive_timeout和wait_timeout参数对sleep连接的影响 interactive_timeout 参数含义:服务器关闭交互式连接前等待活动的秒数.交互式客户端定 ...

  10. 求不小于N且二进制串包含K个1的最小的数字

    给定正整数N,求一个最小正整数M(M>=N),使得M中连续1的个数不小于K. 输入格式:N K 其中N为大整数,只能进行字符串处理 首先要把N化为二进制串,考察这个二进制串的最后K位: 直接把这 ...