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、打撲克牌的方法四:拖拉機,牌局採用四人結對競賽,以搶分升級的方式進行,根據游戲規則,通過搶分或保分升級,取得領先的級數。