2015/4/17 星期五 下午 18:25:04node
對順序表的排序其實就是對結構體中的關鍵字的排序。c++
自定義結構體:
算法
typedef struct node { int age; int height; int width; }Node;
如今想根據其中的age排序,用c語言實現有兩種:c#
一、自定義交換函數,而後用經常使用的交換排序的方法進行排序就好了。這裏用快速排序排序實現:數組
快排實現:dom
//自定義結構體交換 void swap(Node *a, Node *b) //指定排序的節點 { Node t = *a; *a = *b; *b = t; } //快排遞歸實現 void QuickSort(ElemType *elem, int left, int right) //注意這裏是閉區間 { if(left < right) { int temp = elem[right].age; //這裏要指定是按age排序的 int i = left-1; int j = left; while(j < right) { if(elem[j].age <= temp) //這裏也要指定 <= 能夠用<帶換 { ++i; swap(&elem[i], &elem[j]); } j++; } swap(&elem[i+1], &elem[right]); int r = i+1; QuickSort(elem, left, r-1); QuickSort(elem, r+1, right); } }
算法平均複雜度:O(nlogn),最壞狀況複雜度:O(n2)。空間複雜度O(n)。函數
二、 固然c語言中也內置了排序算法qsort,位於stdlib.h頭文件中,核心是用快排實現的。測試
函數原型:ui
void qsort(void *base, int nelem, int width, int (*fcmp)(const void *,const void *));
指針
函數關鍵的比較函數:
這個函數是自定義對對象如何排序的方法。能夠對整數,對字符串,對自定義結構體,均可以排序,從大到小,或者從小到大。比較函數通常這樣寫:
int cmp(const void* a, const void* b) { return (*(Node*)a).age - (*(Node*)b).age; }
結構體節點比較就是這樣寫。返回的是一個整型值,
####也能夠把減號換爲>號,就是從大到小排序的。
比較函數返回大於0,qsort就認爲 a>b , 若是比較函數返回等於0
qsort就認爲a 和b 這兩個元素相等,返回小於零 qsort就認爲 a<b.
主函數中調用:
###qsort(a,10,sizeof(a[0]),cmp);
因爲c++是包括了c語言,因此上面的快排,在c++中依然能運行經過。
這裏,我來介紹一下C++中更好地辦法去排序。
一、使用重載運算符,達到給結構體新的比較方法,來實現排序的目的。說白了就是建立結構體,定義兩個結構體比較的時候,是按哪一個字段比較。直接上代碼:
注意:c++中能夠不帶typedef 來給結構體"披外套.
struct Node { int age; itn height; int width; bool operator<(struct Node b) const //這裏必須加上const { return age < b.age; } };
通過上面的定義後,接着寫
Node a, b; 並給字段賦過值後,再比較a<b. 含義就是a.age < b.age了。
這樣的話,上面的快速排序的代碼,就不用特地指定按age排序了。結構體能夠直接賦值,這裏就不用重載=號了。
交換代碼和上面的同樣。改寫上面的快速排序代碼:
void QuickSort(ElemType *a, int left, int right) { if(left < right) { ElemType temp = a[right]; //這裏不用指定是age,具備通用型。 int i = left-1; int j = left; while(j < right) { if(a[j] < a[right]) { ++i; Swap(&a[j],&a[i]); } j++; } Swap(&a[i+1],&a[right]); int r = i+1; QuickSort(a, left, r-1); QuickSort(a, r+1, right); } }
二、使用sort,一樣c++中也有特有的排序函數,sort,它的內部是不少高效率的排序算法的整合,根據待排序的數據量選擇不一樣的排序方法,是時間最優。
該函數位於頭文件#include <algorithm.h>
中。
函數原型:使用了模板類, 就是第三個參數(自定義排序方式)是可選的。
template< class RandomIt >
void sort( RandomIt first, RandomIt last ) (1);template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp ); (2)
如何使用sort?
一、配合結構體中的重載一塊兒使用:
咱們在上面定義了重載’<‘運算符的結構體,就能夠直接用sort排序了。
直接sort(node,node+n);
兩個參數,至關於數組的始末指針。
不過注意,這裏是按從小到大的順序排的,由於上面重載的時候是<對<號,若是重載小於號的時候,在函數體內寫的倒是age>b.age
,結果就是從大到小排序了。
二、不使用結構體運算符的重載,使用sort的第三個參數(自定義排序方法)來實現排序的效果。
bool cmp(ElemType a, ElemType b) { return a.age > b.age; }
這樣的話主函數裏用的時候寫sort(a,a+n,cmp);
就能排序了。
單鏈表不適合快速排序,雙向鏈表才適合快速排序,這裏咱們用選擇排序法排序單鏈表,用快速排序法,排序雙向鏈表:
單鏈表
定義單鏈表:
typedef struct LinkNode { DataType data; struct LinkNode *next; //指向後繼節點 }Linknode;
有關選擇排序的知識,請看這裏:wikipedia:選擇排序;
直接上代碼:
void Sort(LinkNode *L) { LinkNode *p = L->next; LinkNode *min = p; while(p) { min = p; LinkNode *q = L->next; while(q) { if(q->data < min->data) { min = q; } q = q->next; } Swap(p, min); //這裏很關鍵,如何交換兩個節點的值,而不改變節點的指針指向? p = p->next; } }
下面畫圖來解釋:
實際代碼:
inline void Swap(LinkNode *p, Linknode *q) { LinkNode temp = *p; temp.next = q->next; q->next = p->next; *p = *q; *q = temp; }
雙向鏈表實現快速排序
一、雙向鏈表定義:
struct Node { int data; struct Node *pri, *next; };
二、新建雙鏈表
Node* CreateDulNode(int *a, int n) //將數組元素存到鏈表中 { Node *head = (Node*)malloc(sizeof(Node)); head->next = NULL; head->pri = NULL; Node *p = head; int i = 0; Node *q = NULL; while (i<n) { q = (Node*)malloc(sizeof(Node)); q->data = a[i]; q->next = p->next; q->pri = p; p->next = q; p = q; i++; } q->next = head; head->pri = q; return head; }
三、快速排序 //其實就是數組的排序原理,有些小細節要注意
//調用QuickSort(L->next, L->pri); void QuickSort(Node *Left, Node* right) //閉區間 { if (Left->pri != right) //這裏當right在left左邊是結束 { Node *temp = right; Node *p = Left->pri; Node *q = Left; while (q != right) { if (q->data < temp->data) { p = p->next; Swap(p, q); } q = q->next; } p = p->next; Swap(p, temp); // OutPut2(Left,right); //測試輸出函數 QuickSort(Left, p->pri); QuickSort(p->next, right); } }
四、關鍵的交換函數,不過也和單鏈表的交換差很少了
void Swap(Node *p, Node *q) { Node temp = *p; temp.next = q->next; temp.pri = q->pri; q->next = p->next; q->pri = p->pri; *p = *q; *q = temp; }
五、測試輸出函數
void OutPut2(Node *Left, Node *right) { Node *p = Left; while (p!=right) { cout << p->data << " "; p = p->next; } cout << right->data << " "; //單獨輸出最後一個 cout << endl; }
實驗結果:
總結: 之前排序都是在數組上排序,如今學了鏈表,也想實現快速排序。總之,本質上沒啥區別,算法流程都差很少,只是操做上的不一樣。