数据结构与算法之二 排序

假定,你要为你的生日聚会邀请你的朋友和亲戚。对此,你需要给他们打电话。你正在拥有10,000条记录的电话本中查找名为Steve的电话号码。然而,电话本中的记录是以随意顺序存储的。要在这样一个目录中查找你朋友的电话号码,你需要按顺序在目录中浏览每个条目。这将非常耗时,你如何解决此问题呢?

节省时间和高效搜索数据的简单解决方案是排序。

排序是按照某些预定义的顺序或序列排列数据的过程。此顺序可以是升序或降序。

如果数据被排序,则可以直接转到存储以‘S’开头的姓名部分,因此减少了要遍历的记录数。

选择排序算法

通过使用一算法实现在程序中排序。

一些排序算法有:

冒泡(Bubble)排序

选择排序

插入排序

壳(Shell)排序

合并排序

快速排序

堆排序

要选择合适的算法,你需要考虑以下方面:

执行时间

存储空间

编程工作

冒泡排序算法:

是最简单的排序算法之一

此算法具有二次方程增长阶,因此适合仅排序小列表

通过列表重复扫描、比较相邻元素和按错误顺序交换,此算法会有作用.

编写一算法以实现冒泡排序。

冒泡排序的算法是:

1.设置通道(圈数) = 1。

2.重复步骤3  区分0
到n – 1通道中的j。

1.如果索引j处的元素大于索引j + 1处的元素,则交换这两个元素。

3.按1递增通道;圈数加1

4.如果通道 <= n-1,则转到第2步。

排序算法的效率按照比较次数来测量。

在冒泡排序中,通道1内有n–
1 次比较,通道2中有n– 2
次比较,依此类推。

比较总数= (n – 1) + (n – 2) + (n – 3) + … + 3 + 2 + 1= n(n
– 1)/2

n(n – 1)/2是O(n2)
阶的级数。因此,冒泡排序算法是阶O(n2)的算法。

什么是冒泡排序算法的增长阶?

答案:

n –
1 次比较

答案:

冒泡排序算法具有二次方增长阶

当实现冒泡排序算法时,在通道1中将执行多少次比较?

答案:

n –1
次比较

使用选择排序来排序数据

选择排序算法:

选择排序还具有二次方程增长阶,且因此仅适用于排序小的列表。

选择排序通过列表反复扫描,每次扫描选择一项,然后将这一项移动到列表中正确的位置。

要理解选择排序算法的实现,考虑数组中存储的未排序的数字列表。每次都寻找最小值,将最小值往前放

编写一算法以实现选择排序。

选择排序的算法:

1.重复步骤2和3区分0
到n -2通道中的j

2.找出arr[j]到arr[n
– 1]中的最小值:

a.设置min_index = j

b.重复步骤c区分j + 1
到n – 1的i

c.如果arr[i] < arr[min_index]:

i.  
min_index = i

3.将arr[j]与arr[min_index]交换

在选择排序中,在查找最小元素的通道1中有n–
1次比较。在查找第二个最小元素的通道2中有n -2次比较,依此类推。

比较总数 = (n – 1) + (n – 2) + (n – 3) + … + 3 + 2 + 1 =n(n
– 1)/2

n(n – 1)/2是O(n2)
阶的级数。因此,选择排序算法是阶O(n2)的算法。

插入排序算法:

具有二次方程增长阶,且因此仅用于排序小列表。

如果需要排序的列表几乎已经排序,则插入排序比冒泡排序和选择排序更有效率。

要理解插入排序算法的实现,考虑数组中存储的未排序的数字列表。

要使用插入排序算法排序此列表:

你需要将列表分为两个子列表,即排序和未排序。

若要通过使用插入排序排序大小为n的列表,您需要执行(n–
1) 次通道。

最佳用例效率:

当列表已经被排序时产生最佳用例。

在这种情况下,您必须在每个通道中仅做一次比较。

在n– 1
次通道中,您将需要做n
– 1次比较。

插入排序的最佳用例效率是O(n)阶的。

最糟用例效率:

当列表按反向顺序排序时产生最糟用例效率。

在这种情况下,您需要在第1个通道中做1次比较,在第二个通道中做2次比较,在第3个通道中做3次比较,在第n–
1 个通道中做n
– 1次比较。

插入排序的最糟用例效率是O(n2)阶的。

销售经理对2004-2006念市场上最佳冷饮销售员进行调查。David是一名软件开发人员,他有一个冷饮品牌及其销售数据的文件。
David 必须向销售经理提供排序好的数据。文件总的数据或多或少都要进行排序。存储此数据最有效率的排序算法是哪个?为什么?

记录是以随意顺序存储的。

答案:

当列表部分排序时,插入排序提供了比泡泡排序和选择排序更好的有效。因此David应使用插入排序算法。

壳排序算法:

只要此列表已经部分排序且造成平均用例中的无效解决方案,则插入算法是高效算法。

为了克服此限制,计算机科学家D.L. Shell提议改进插入排序算法。

新的算法称为壳(Shell)排序,是按照他的姓名命名的。

壳排序:

通过按若干位置的距离形成多个子列表分隔元素并进行比较来改进插入排序算法

对每个子列表应用插入排序使元素朝着其正确的位置移动

帮助元素快速靠近正确的位置,因此减少了比较的次数

小结

在本章中,你已经学到:

排序是按照某些预定义的顺序或关键值排列数据的过程。此顺序可以是升序或降序。

用于排序数据有各种排序算法。其中一些如下:

冒泡排序

选择排序

插入排序

壳排序

合并排序

快速排序

堆排序

若要选择合适的算法,您需要考虑以下内容:

执行时间

存储空间

编程工作

冒泡排序和选择排序算法具有二次方程增长阶,且因此仅适用于排序小的列表。

插入排序执行不同次数的比较,这取决于最初的元素分阶。当元素已经处于排序阶,则插入排序需要进行极少比较。

如果需要排序的列表几乎已经排序,则插入排序比冒泡排序和选择排序更有效率。

通过比较按若干位置的距离分隔的元素,壳排序改善了插入排序。这帮助元素快速靠近正确的位置,因此减少了比较的次数。

/**********************************************************/

/*描述:编写程序将10个学生的得分存储到数组中。通过使用冒泡排序算法,来排序数组中的元素,排序数组后,显示排序后数组的元素*/
using System;

class List
{
	//定义长度为20的整型数组
	private int[]a=new int[20];	//20是最大长度.

	//数组的个数
	private int n;
	//定义一个方法读取数据元素到数组
	public void read()
	{
			//获得
			while(true)
			{
				Console.WriteLine("请输入数组元素的个数<20之内>:");
				string s=Console.ReadLine();
				n=Int32.Parse(s);//转换为整型.Convert.ToInt32(s)
				if(n<=20)
					break;	//跳出循环
				else
					Console.WriteLine("\n数组只能够容纳20个数组元素.\n");
			}//while结束.
			Console.WriteLine("");
			Console.WriteLine("----------------------------------");
			Console.WriteLine("-----请输入数组元素---------------");
			Console.WriteLine("----------------------------------");
			//用户将数句元素输入数组
			for(int i=0;i<n;i++)
			{
				Console.Write("<"+(i+1)+">");
				string s1=Console.ReadLine();
				a[i]=Int32.Parse(s1);
			}//<1>20 <2>20 <3>90
	}

	//*************************显示数组元素*************************
	public void display()
	{
		Console.WriteLine("");
		Console.WriteLine("-------------------------------------------");
		Console.WriteLine("------------排序过后的元素-----------------");
		Console.WriteLine("-------------------------------------------");	

		for(int j=0;j<n;j++)
		{
			Console.WriteLine(a[j]);
		}
	}
	/***************冒泡排序方法***************************/
	public void BubbleSortArray()
	{
		//圈数1--->n-1
		for(int i=1;i<=n-1;i++)	//i:1;不是数组下标,是通道次数
		{
			//里面做的工作是两个相邻数字的比较;如果不符合升序排列,则交换.j指数组下标.
			for(int j=0;j<n-i;j++)	//注意:比较n-i次
			{
				if(a[j]>a[j+1])	//则说明不符合升序排列,需要交换
				{
					int temp;
					temp =a[j];
					a[j]=a[j+1];
					a[j+1]=temp;
				}
			}//内层交换结束
		}//圈数循环结束.
	}
	/******************Main()方法*********************/
	public static void Main(string[]args)
	{
		List myList=new List();
		myList.read();	//读取数据元素

		myList.BubbleSortArray();	//调用冒泡排序算法
		myList.display();				  //显示数组元素
		Console.WriteLine("\n\n按任意键退出.");
		Console.Read();
	}
}

--------------------------

/*
描述:使用选择排序,来排列包含10个学生得分的整数数组,升序排列.
*/
using System;

class Selection
{
	//定义数组的大小
	private int[]a=new int[20];
	//数组元素的个数.
	private int n;
	//定义接受数组元素的函数
	void read()
	{
		while(true)
		{
			Console.WriteLine("请输入数组元素的个数:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			if(n<=20)
				break;
			else
				Console.WriteLine("\n数组只能够接收20个元素.\n");
		}
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------请输入数组元素---------");
		Console.WriteLine("---------------------------------");
		//用户输入数据
		for(int i=0;i<n;i++)
		{
			Console.Write("<"+(i+1)+">");
			string	s1=Console.ReadLine();
			a[i]=Int32.Parse(s1);
		}
	}
	//显示数组内容的函数
	void display()
	{
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------排序后的数组元素-------");
		Console.WriteLine("---------------------------------");
		for(int j=0;j<n;j++)
		{
			Console.WriteLine(a[j]);
		}
	}
/*
	选择排序算法:每次选择最小值,将其依次往前排;借助于下标标记来实现.
*/
	public void SelectionSortArray()
	{
		//外面进行了n-1圈
		for(int i=0;i<n-1;i++)
		{
			//定义个指示最小值标记的变量
			int min_index=i;
			//查找选择最小值所对应的标记(下标)
			for(int j=i+1;j<=n-1;j++)
			{
				//判断如果有值比,最小值下标对应的数还小,则将该值对应的下标给min_index
				if(a[j]<a[min_index])
					min_index=j;
			}//结束寻找最小值下标
			//交换:a[i]<-->a[min_index]
			swap(i,min_index);	//调用交换方法.
		}
	}
	//交换两个值的方法
	public void swap(int x,int y)
	{
		int temp;
		temp=a[x];
		a[x]=a[y];
		a[y]=temp;
	}
	//类的主方法
	public static void Main()
	{
		Selection sec=new Selection();
		sec.read();
		sec.SelectionSortArray();
		sec.display();
		Console.WriteLine("\n\n请按任意键结束!.");
		Console.Read();
	}
}

---------------------

/*
描述:使用插入排序,来排列包含10个学生得分的整数数组。
*/
using System;

class Insertion
{
	//定义数组的大小
	private int[]a=new int[20];
	//数组元素的个数.
	private int n;
	//定义接受数组元素的函数
	void read()
	{
		while(true)
		{
			Console.WriteLine("请输入数组元素的个数:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			if(n<=20)
				break;
			else
				Console.WriteLine("\n数组只能够接收20个元素.\n");
		}
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------请输入数组元素---------");
		Console.WriteLine("---------------------------------");
		//用户输入数据
		for(int i=0;i<n;i++)
		{
			Console.Write("<"+(i+1)+">");
			string	s1=Console.ReadLine();
			a[i]=Int32.Parse(s1);
		}
	}
	//显示数组内容的函数
	void display()
	{
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------排序后的数组元素-------");
		Console.WriteLine("---------------------------------");
		for(int j=0;j<n;j++)
		{
			Console.WriteLine(a[j]);
		}
	}
	//****使用选择排序的方法
public void InsertionSortArray()
{
		//重复n-1次来将为排序列表数据放入已排序列表
		for(int i=1;i<n;i++)
		{
		int temp=a[i];
		int j=i-1;
		//如果j>=0或大于临时值,则执行如下操作
		while((j>=0)&&(a[j]>temp))
		{
			a[j+1]=a[j];
			j--;
		}
		a[j+1]=temp;
	}
}
	//交换两个值的方法
	public void swap(int x,int y)
	{
		int temp;
		temp=a[x];
		a[x]=a[y];
		a[y]=temp;
	}
	//类的主方法
	public static void Main()
	{
		Insertion sec=new Insertion();
		sec.read();
		sec.InsertionSortArray();
		sec.display();
		Console.WriteLine("\n\n请按任意键结束!.");
		Console.Read();
	}
}

------------------------------------------------------------------------

/*
描述:使用插入排序,来排列包含10个学生得分的整数数组。
*/
using System;

class ShellSorter
{
	//数组元素的个数.
	private static int n=0;
	//定义数组的大小
	private int[]a;
	//定义接受数组元素的函数
	void read()
	{
		while(true)
		{
			Console.WriteLine("请输入数组元素的个数:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			a=new int[n];
			if(n<=20)
				break;
			else
				Console.WriteLine("\n数组只能够接收20个元素.\n");
		}
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------请输入数组元素---------");
		Console.WriteLine("---------------------------------");
		//用户输入数据
		for(int i=0;i<n;i++)
		{
			Console.Write("<"+(i+1)+">");
			string	s1=Console.ReadLine();
			a[i]=Int32.Parse(s1);
		}
	}
	//显示数组内容的函数
	void display()
	{
		Console.WriteLine("");
		Console.WriteLine("---------------------------------");
		Console.WriteLine("----------排序后的数组元素-------");
		Console.WriteLine("---------------------------------");
		for(int j=0;j<n;j++)
		{
			Console.Write("  "+a[j]);
		}
	}
	//****使用希尔排序的方法
        public void ShellSort()
        {
            for (int step = a.Length/ 2; step >= 1; step = step / 2)
            {
                for (int i = step; i < a.Length; i+=step)
                {
                    int temp = a[i];
                    int j = i - step;
                    while (j >= 0 && temp < a[j])
                    {
                        a[j + step] = a[j];
                        j-=step;
                    }
                    a[j + step] = temp;
                }
            }
        }
	//交换两个值的方法
	public void swap(int x,int y)
	{
		int temp;
		temp=a[x];
		a[x]=a[y];
		a[y]=temp;
	}
	//类的主方法
	public static void Main()
	{
		ShellSorter sec=new ShellSorter();
		sec.read();
		sec.ShellSort();
		sec.display();
		Console.WriteLine("\n\n请按任意键结束!.");
		Console.Read();
	}
}
时间: 2024-12-29 12:16:42

数据结构与算法之二 排序的相关文章

【数据结构与算法】选择排序

选择排序没什么好说的,直接上代码吧 public class SelectSort { public void selectSort(int[] in) { int inLength = in.length; int minIndex = 0; for (int i = 0; i < inLength; i++) { minIndex = i; for (int j = i + 1; j < inLength; j++) { if (in[j] < in[minIndex]) { min

【数据结构与算法】希尔排序

希尔排序的时间复杂度是O(n^1.3)~O(n^2),空间复杂度是O(1). 代码如下: /** * 源码名称: ShellSort.java * 日期:2014-08-11 * 程序功能:希尔排序 * 版权:[email protected] * 作者:A2BGeek */ public class ShellSort { public void shellSort(int[] in) { int length = in.length; int span = length / 2; int i

Java数据结构和算法(二)树的基本操作

Java数据结构和算法(二)树的基本操作 一.树的遍历 二叉树遍历分为:前序遍历.中序遍历.后序遍历.即父结点的访问顺序 1.1 前序遍历 基本思想:先访问根结点,再先序遍历左子树,最后再先序遍历右子树即根-左-右.图中前序遍历结果是:1,2,4,5,7,8,3,6. // 递归实现前序遍历 public void preOrder() { System.out.printf("%s ", value); if (left != null) { left.preOrder1(); }

数据结构与算法之--高级排序:shell排序和快速排序【未完待续】

高级排序比简单排序要快的多,简单排序的时间复杂度是O(N^2),希尔(shell)排序的是O(N*(logN)^2),而快速排序是O(N*logN). 说明:下面以int数组的从小到大排序为例. 希尔(shell)排序 希尔排序是基于插入排序的,首先回顾一下插入排序,假设插入是从左向右执行的,待插入元素的左边是有序的,且假如待插入元素比左边的都小,就需要挪动左边的所有元素,如下图所示: ==> 图1和图2:插入右边的temp柱需要outer标记位左边的五个柱子都向右挪动 如图3所示,相比插入排序

数据结构与算法系列二(复杂度分析)

1.引子 1.1.为什么要学习数据结构与算法? 有人说,数据结构与算法,计算机网络,与操作系统都一样,脱离日常开发,除了面试这辈子可能都用不到呀! 有人说,我是做业务开发的,只要熟练API,熟练框架,熟练各种中间件,写的代码不也能“飞”起来吗? 于是问题来了:为什么还要学习数据结构与算法呢? #理由一: 面试的时候,千万不要被数据结构与算法拖了后腿 #理由二: 你真的愿意做一辈子CRUD Boy吗 #理由三: 不想写出开源框架,中间件的工程师,不是好厨子 1.2.如何系统化学习数据结构与算法?

数据结构与算法之——八大排序算法

附:关于这个主题,网上好的文章已经数不胜数,本篇是整合后的文章. 正文: 一.概述 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 本文所指八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短: 二.排序算法详述 1.

Java数据结构和算法(二)——数组

上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖——数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要的数据结构,当然每种语言对数组的实现和处理也不相同,但是本质是都是用来存放数据的的结构,这里我们以Java语言为例,来详细介绍Java语言中数组的用法. 1.Java数组介绍 在Java中,数组是用来存放同一种数据类型的集合,注意只能存放同一种数据类型. ①.数组的声明 第一种方式: 数据类型 []

数据结构与算法复习(一) 排序算法(I)

这篇文章将会介绍最常见的排序算法(使用 JavaScript 语言实现) PS:这里我会尽量使用语言无关的语法去写,大家不要太在意语言,重要的是算法的实现思路 1.冒泡排序 将数组分为有序区(左边)和无序区(右边) 每次从无序区的最后一个元素开始,一直向前冒泡到无序区的第一个位置,使其变成有序 function swap(A, i, j) { if (i === j) return [A[i], A[j]] = [A[j], A[i]] } function bubbleSort(A) { fo

数据结构与算法之二叉搜索树

与链表不同,树是一种非线性的数据结构.树中最常用的是二叉树,二叉树限制了子树的数量,也就是每个结点的子树至多2个,并且这两个子树是有顺序的.而二叉搜索树(二叉查找树,二叉排序树)是指根节点的关键字大于左子树的,而小于右子树,并且,左右子树也是一颗二叉搜索树.也就是说中序遍历一颗二叉搜索树,它的输出是从小到大排序好的. 除了普通的二叉搜索树之外,还有很多关于它的变形. 二叉平衡搜索树,即即是一颗二叉平衡树,也是一颗搜索树,平衡树即任意一个结点的左子树的高度与右子树的高度之差的绝对值不大于1. 红黑