算法導論筆記,第2章 循環不變式與插入排序

本章的重點是循環不變式。也就是在一個循環中存在着某些不變的量。它相似於數學概括法的概括步驟:node

  1. 初始化:在循環第一輪迭代開始以前,應該是正確的。
  2. 保持:若是在循環的某一次迭代開始以前它是正確的,那麼在下一次迭代開始以前,它也應該保持正確。
  3. 終止:當循環結束時,不變式給了咱們一個有用的性質,它有助於說明算法是正確的。

咱們在設計一個算法、分析一個算法的時候,要適當應用循環不變式來簡化分析工做、證實算法的正確性。算法

書中舉例插入排序:數組

 n個元素的待排序數組A,下標是從1到n。 j從2開始一直遍歷到大於n(此時會退出循環)。循環不變式的量是:A[1...j-1]這個子數組是已排序的。 spa

  1. 初始化:j=2, 此時A[1...j-1]只包含一個元素,因此它是正確的(已排序的)。
  2. 保持:經過將A[j-1], A[j-2]....等元素向右移動一個位置,直到找到A[j]的適當位置爲止,來保持A[1...j-1]已排序。
  3. 終止:當j大於n時,外層for循環會結束。

經過這個簡單的約束規則,能夠很容易地默寫出插入排序的實現代碼:設計

void insert_sort(int* A, int n) {
  for (int j = 1; j < n;j++) {
    int key = A[j];
    int i = j-1;
    for (; i>=0 && key < A[i]; i--) {
        A[i+1] = A[i];
    }
    A[i+1] = key;
  }
}

存在着兩層for循環,因此算法的時間複雜度是O(n^2). 
只用了一個臨時變量key, 因此空間複雜度是O(1)code

擴展思考一下:插入排序能夠對鏈表進行排序嗎?blog

應該是能夠的。假設存在鏈表list. 每次從list中摘取一個節點,將它插入到sortedList中,一直到list爲空。循環不變式sortedList是有序的鏈表。排序

因而循環不變式是:數學

  1. 初始化:一開始sortedList是list的頭結點,因此它是正確的(已排序的)。
  2. 保持:經過依次從list中摘取一個節點,在sortedList的合適位置中插入,來保持sortedList是有序的。
  3. 終止:list沒有更多節點是,外層for循環會結束。

先定義一下listit

typedef struct List{
  int item;
  struct List* next;
} List;
List* AddList(List* l, int item);
#include "list.h"
List* AddList(List* l, int item) {
  List* node = new(List);// (List*) malloc(sizeof(List));
  node->item = item;
  node->next = 0;
  if (l) {
    node->next = l->next;
    l->next = node;
    return l;
  }
  return node;
}

再來實現一下鏈表的插入排序

List* insert_sortL(List* list) {
  List* head = list;
  if (head == NULL) {
    return NULL;
  }

  List* sortedList =  head;//初始化,sortedList只有一個節點。
  List* j = head->next;
  sortedList->next = NULL;//將head從list中摘取出來
  for (; j != NULL;) {
    List* current = j;//注意摘取節點j(current)的次序
    j = j->next;
    current->next = NULL;
    int k = current->item;
    if (k < sortedList->item) {//若是比sortedList的頭結點小,則須要更新頭結點
      current->next = sortedList;
      sortedList = j;
      continue;
    }

    List* i = sortedList;//將current插入到sortedList的合適位置
    for (; i->next != NULL && k > i->next->item; i = i->next) {
    }
    current->next = i->next;
    i->next = current;
  }
  return sortedList;
}
相關文章
相關標籤/搜索