1. 52张扑克牌排序算法
简单:给每个花色一个值:
黑桃 39,红桃 26,草花 13,方块 0
然后计算每张扑克的value ,我们这样定义value
value = 花色+点数,例如 红桃5的value = 26+5 = 31
给每张扑克牌定义好value,在从大到小排列.现成的算法.我就不赘述了.
2. 常见的几种排序算法总结
对于非科班生的我来说,算法似乎对我来说是个难点,查阅了一些资料,趁此来了解一下几种排序算法。
首先了解一下,什么是程序
关于排序算法通常我们所说的往往指的是内部排序算法,即数据记录在内存中进行排序。
排序算法大体可分为两种:
一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。
另一种是非比较排序,时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等
冒泡排序它重复地走访过要排序的元素,一次比较相邻两个元素,如果他们的顺序错误就把他们调换过来,直到没有元素再需要交换,排序完成。这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢“浮”到数列的顶端。
选择排序类似于冒泡排序,只不过选择排序是首先在未排序的序列中找到最小值(最大值),放到序列的起始位置,然后再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾,以此类推,直到所有元素均排序完毕。
插入排序比冒泡排序和选择排序更有效率,插入排序类似于生活中抓扑克牌来。
插入排序具体算法描述,以数组[3, 2, 4, 5, 1]为例。
前面三种排序算法只有教学价值,因为效率低,很少实际使用。归并排序(Merge sort)则是一种被广泛使用的排序方法。
它的基本思想是,将两个已经排序的数组合并,要比从头开始排序所有元素来得快。因此,可以将数组拆开,分成n个只有一个元素的数组,然后不断地两两合并,直到全部排序完成。
以对数组[3, 2, 4, 5, 1] 进行从小到大排序为例,步骤如下:
有了merge函数,就可以对任意数组排序了。基本方法是将数组不断地拆成两半,直到每一半只包含零个元素或一个元素为止,然后就用merge函数,将拆成两半的数组不断合并,直到合并成一整个排序完成的数组。
快速排序(quick sort)是公认最快的排序算法之一,有着广泛的应用。
快速排序算法步骤
参考:
常用排序算法总结(一)
阮一峰-算法总结
3. 最快的排序算法是什么
最快的排序算法是什么,很多人的第一反应是快排,感觉QuickSort 当然应该最快了,其实并非如此,快排是不稳定的,最坏情况下,快排序并不是最优,Java7 中引入的 TimSort 就是一个结合了插入排序和归并排序的高效算法.
Timsort最早是 Tim Peters 于2001年为 python 写的排序算法。自从发明该算法以来,它已被用作Python,Java,Android平台和GNU Octave中的默认排序算法。
关于此算法的详细描述参见 http://svn.python.org/projects/python/trunk/Objects/listsort.txt
看看它与另外两个高效排序算法的比较
相比之下, TimSort 的最佳,平均和最坏情况综合起来最佳。在数据量比较少(<=64)的情况下,它直接用 Insert Sort,否则使用 MergeSort + BinarySearch 来提高排序效率
下面写一个给扑克牌排序的例子,比较一下冒泡,插入,快排,归并排序,TimSort的性能:
然后分别用以上5种排序方法来做下性能比较
将1000 副牌打乱顺序的扑克牌排序下来,结果如下
但是 TimSort 也有一个问题, 在 JDK7 的描述中提到它有如下兼容性问题
所以在JDK7以后,实现Comparable接口的比较器需要满足以下三个约束条件:
1) 自反性:x,y 的比较结果和 y,x 的比较结果相反。
2) 传递性:x>y, y>z,则 x>z。
3) 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同。
如果你的比较方法违反了以上的约束,要么你不使用这个新的算法,还是回到传统的归并排序
要么修改你的比较器以符合上述的约束条件。
举两个例子如下
4. 八大算法
算法中比较常用的有八种算法,基本算法的题,都是依靠这些基础算法或者结合使用出题的,所以要学会基础算法,才有可能去更好的掌握算法题。
插入排序,又叫直接插入排序。实际中,我们玩扑克牌的时候,就用了插入排序的思想。
基本思想:在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。
希尔排序,又称缩小增量法。其基本思想是:
1>先选定一个小于N的整数gap作为第一增量,然后将所有距离为gap的元素分在同一组,并对每一组的元素进行直接插入排序。然后再取一个比第一增量小的整数作为第二增量,重复上述操作…
2>当增量的大小减到1时,就相当于整个序列被分到一组,进行一次直接插入排序,排序完成。
选择排序,即每次从待排序列中选出一个最小值,然后放在序列的起始位置,直到全部待排数据排完即可。
如何进行堆排序呢?
步骤如下:
1、将堆顶数据与堆的最后一个数据交换,然后对根位置进行一次堆的向下调整,但是调整时被交换到最后的那个最大的数不参与向下调整。
2、完成步骤1后,这棵树除最后一个数之外,其余数又成一个大堆,然后又将堆顶数据与堆的最后一个数据交换,这样一来,第二大的数就被放到了倒数第二个位置上,然后该数又不参与堆的向下调整…反复执行下去,直到堆中只有一个数据时便结束。此时该序列就是一个升序。
冒泡排序,该排序的命名非常形象,即一个个将气泡冒出。冒泡排序一趟冒出一个最大(或最小)值。
快速排序是公认的排序之王,快速排序是Hoare于1962年提出的一种二叉树结构的交换排序算法,其基本思想为:
任取待排序元素序列中的某元素作为基准值,按照该基准值将待排序列分为两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右序列重复该过程,直到所有元素都排列在相应位置上为止。
归并排序是采用分治法的一个非常典型的应用。其基本思想是:将已有序的子序合并,从而得到完全有序的序列,即先使每个子序有序,再使子序列段间有序。
计数排序,又叫非比较排序。顾名思义,该算法不是通过比较数据的大小来进行排序的,而是通过统计数组中相同元素出现的次数,然后通过统计的结果将序列回收到原来的序列中。
5. 几种常用的排序算法比较
排序,从小大,0坐标的在下面,即排序后小的在下面,大的在上面。
1,冒泡Bubble:从第0个开始,一直往上,与相邻的元素比较,如果下面的大,则交换。
Analysis:
Implementation:
void BubbleSort(int *pData, int iNum)
2,插入Insertion:与打扑克牌时整理牌很想象,假定第一张牌是有序的,从第二张牌开始,拿出这张牌来,往下比较,如果有比这张牌大的,则把它拨到上一个位置,直到找到比手上的这张更小的(或到顶了),
则把手上的这张牌插入到这张更小的牌的后面。
Analysis:
Implementation:
void InsertionSort(int *list, int length)
{
int i, j, temp;
for (i = 1; i < length; i++)
{
temp = list[i];
j = i - 1;
while ((j >= 0) && (list[j] > temp))
{
list[j+1] = list[j];
j--;
}
list[j+1] = temp;
}
}
3,选择Selection:从所有元素中找到最小的放在0号位置,从其它元素(除了0号元素)中再找到最小的,放到1号位置,......。
Analysis:
Implementation:
void SelectionSort(int data[], int count)
{
int i, j, min, temp;
for (i = 0; i < count - 1; i++)
{
/* find the minimum */
min = i;
for (j = i+1; j < count; j++)
{
if (data[j] < data[min])
{
min = j;
}
}
/* swap data[i] and data[min] */
temp = data[i];
data[i] = data[min];
data[min] = temp;
}
}
4,快速Quick:先拿出中间的元素来(值保存到temp里),设置两个索引(index or pointer),一个从0号位置开始往最大位置寻找比temp大的元素;一个从最大号位置开始往最小位置寻找比temp小的元素,找到了或到顶了,则将两个索引所指向的元素
互换,如此一直寻找交换下去,直到两个索引交叉了位置,这个时候,从0号位置到第二个索引的所有元素就都比temp小,从第一个索引到最大位置的所有元素就都比temp大,这样就把所有元素分为了两块,然后采用前面的办法分别排序这两个部分。总的来
说,就是随机找一个元素(通常是中间的元素),然后把小的放在它的左边,大的放右边,对左右两边的数据继续采用同样的办法。只是为了节省空间,上面采用了左右交换的方法来达到目的。
Analysis:
Implementation:
void QuickSort(int *pData, int left, int right)
{
int i, j;
int middle, iTemp;
i = left;
j = right;
middle = pData[(left + right) / 2]; //求中间值
do
{
while ((pData[i] < middle) && (i < right)) //从左扫描大于中值的数
i++;
while ((pData[j] > middle) && (j > left)) //从右扫描小于中值的数
j--;
if (i <= j) //找到了一对值
{
//交换
iTemp = pData[i];
pData[i] = pData[j];
pData[j] = iTemp;
i++;
j--;
}
} while (i <= j); //如果两边扫描的下标交错,就停止(完成一次)
//当左边部分有值(left<j),递归左半边
if(left < j)
QuickSort(pData, left, j);
//当右边部分有值(right>i),递归右半边
if(right > i)
QuickSort(pData, i, right);
}
5,希尔Shell:是对Insertion Sort的一种改进,在Insertion Sort中,从第2个位置开始取出数据,每次都是与前一个(step/gap==1)进行比较。Shell Sort修改为,在开始时采用较大的步长step,
从第step位置开始取数据,每次都与它的前step个位置上的数据进行比较(如果有8个数据,初始step==4,那么pos(4)与pos(0)比较,pos(0)与pos(-4),pos(5)与pos(1),pos(1)与pos(-3),
...... pos(7)与pos(3),pos(3)与pos(-1)),然后逐渐地减小step,直到step==1。step==1时,排序过程与Insertion Sort一样,但因为有前面的排序,这次排序将减少比较和交换的次数。
Shell Sort的时间复杂度与步长step的选择有很大的关系。Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。但是它相对比较简单,它适合
于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。
Analysis:
Implementation:
template<typename RandomIter, typename Compare>
void ShellSort(RandomIter begin, RandomIter end, Compare cmp)
{
typedef typename std::iterator_traits<RandomIter>::value_type value_type;
typedef typename std::iterator_traits<RandomIter>::difference_type diff_t;
diff_t size = std::distance(begin, end);
diff_t step = size / 2;
while (step >= 1)
{
for (diff_t i = step; i < size; ++i)
{
value_type key = *(begin+i);
diff_t ins = i; // current position
while (ins >= step && cmp(key, *(begin+ins-step)))
{
*(begin+ins) = *(begin+ins-step);
ins -= step;
}
*(begin+ins) = key;
}
if(step == 2)
step = 1;
else
step = static_cast<diff_t>(step / 2.2);
}
}
template<typename RandomIter>
void ShellSort(RandomIter begin, RandomIter end)
{
typedef typename std::iterator_traits<RandomIter>::value_type value_type;
ShellSort(begin, end, std::less<value_type>());
}
6,归并Merge:先将所有数据分割成单个的元素,这个时候单个元素都是有序的,然后前后相邻的两个两两有序地合并,合并后的这两个数据再与后面的两个合并后的数据再次合并,充分前面的过程直到所有的数据都合并到一块。
通常在合并的时候需要分配新的内存。
Analysis:
Implementation:
void Merge(int array[], int low, int mid, int high)
{
int k;
int *temp = (int *) malloc((high-low+1) * sizeof(int)); //申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
int begin1 = low;
int end1 = mid;
int begin2 = mid + 1;
int end2 = high;
for (k = 0; begin1 <= end1 && begin2 <= end2; ++k) //比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
{
if(array[begin1]<=array[begin2])
{
temp[k] = array[begin1++];
}
else
{
temp[k] = array[begin2++];
}
}
if(begin1 <= end1) //若第一个序列有剩余,直接拷贝出来粘到合并序列尾
{
memcpy(temp+k, array+begin1, (end1-begin1+1)*sizeof(int));
}
if(begin2 <= end2) //若第二个序列有剩余,直接拷贝出来粘到合并序列尾
{
memcpy(temp+k, array+begin2, (end2-begin2+1)*sizeof(int));
}
memcpy(array+low, temp, (high-low+1)*sizeof(int));//将排序好的序列拷贝回数组中
free(temp);
}
void MergeSort(int array[], unsigned int first, unsigned int last)
{
int mid = 0;
if (first < last)
{
mid = (first+last)/2;
MergeSort(array, first, mid);
MergeSort(array, mid+1,last);
Merge(array,first,mid,last);
}
}
6. 有个扑克牌找规律的题目
#include
void main()
{
int f=0;
int a[1002],n,i;
printf("please input the total numble:\n");
scanf("%d",&n);
for(i=1;i1)
{
for(i=1;i
7. 怎么打扑克牌啊!
打扑克牌新手教程如下:
1、打扑克牌的方法一:斗地主,该游戏由三人个玩一副牌,地主是一方,其余两家为另一方,双方对战,先出完的一方胜。出牌规则类似跑得快。
2、打扑克牌的方法二:跑得快,也叫争上游,负方手中所剩的牌的张数为负分基数,一张没出基数乘4倍;出牌不到1/4基数乘3倍;出牌不到1/2基数乘2倍,赢方得分为3个负方的负分之和,但记为正分。
3、打扑克牌的方法三:锄大地,也叫大老二,首家可以出任何一种合法的牌型,首家出牌后,下家所出的牌张数必须和首家的相同,同时比首家所出的牌大;下家也可以Pass表示不出牌,由再下一家继续出牌。如果连续三家都Pass,这时最后出牌的一家可以重新打出新的牌型,如此继续,直到一人手中的牌全部打光为止。
4、打扑克牌的方法四:拖拉机,牌局采用四人结对竞赛,以抢分升级的方式进行,根据游戏规则,通过抢分或保分升级,取得领先的级数。