鏈表的排序

鏈表的排序

2015/4/17 星期五 下午 18:25:04node

1、順序表的排序

對順序表的排序其實就是對結構體中的關鍵字的排序。c++

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 *));   指針

    參數含義:1 待排序數組首地址。 2 數組中待排序元素數量。 3 各元素的佔用空間大小。 4 指向函數的指針
  • 函數關鍵的比較函數:
    這個函數是自定義對對象如何排序的方法。能夠對整數,對字符串,對自定義結構體,均可以排序,從大到小,或者從小到大。比較函數通常這樣寫:

    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++中更好地辦法去排序。

一、使用重載運算符,達到給結構體新的比較方法,來實現排序的目的。說白了就是建立結構體,定義兩個結構體比較的時候,是按哪一個字段比較。直接上代碼:
注意: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使用的c++中的模板template, 就能夠對任何定義了比較關係的集合進行排序了。模板類,至關於純面嚮對象語言,如c#和Java,中的泛型概念。
  • 如何使用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);就能排序了。

2、鏈式表的排序

  單鏈表不適合快速排序,雙向鏈表才適合快速排序,這裏咱們用選擇排序法排序單鏈表,用快速排序法,排序雙向鏈表:

  • 單鏈表
    定義單鏈表:

    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;
      }

    實驗結果:

    總結: 之前排序都是在數組上排序,如今學了鏈表,也想實現快速排序。總之,本質上沒啥區別,算法流程都差很少,只是操做上的不一樣。

相關文章
相關標籤/搜索