數據結構與算法

最大子序列和(maxSubSeqSum)

  • 時間複雜度:T(N)=O(N3)
int MaxSubSeqSum(int arrays[],int length){
    int i,j,k,thisSum=0,maxSum=0;
    for(i=0;i<length;i++){
        for(j=i;j<length;j++){
            thisSum=0;
            for(k=i;k<=j;k++){
                thisSum+=arrays[k];
            }
            if(thisSum>maxSum)maxSum=thisSum;
        };
    }
    return maxSum;
}
最大子序列和改進1(maxSubSeqSum)
  • 時間複雜度:T(N)=O(N2)
int MaxSubSeqSum(int arrays[],int length){
    int i,j,thisSum=0,maxSum=0;
    for(i=0;i<length;i++){//i是子列左端
        thisSum=0;//從arrays[i]到arrays[j]的子序列和
        for(j=i;j<length;j++){//j是子序列右端
            thisSum+=arrays[j];
            if(thisSum>maxSum)maxSum=thisSum;//若是本次求和大於最終結果,更新maxSum
        };
    }
    return maxSum;
}
最大子序列和(maxSubSeqSum)--分治法

算法複雜度:T(N)=O(NlgN)node

int MaxSubSeqSum(int arrays[], int left, int right) {
    int sum = 0;
    if (left == right) {
        if (arrays[left] > 0)return arrays[left];
        else sum = 0;
    } else {
        int middle = (left + right) / 2;
        int leftSum = MaxSubSeqSum(arrays, left, middle);
        int rightSum = MaxSubSeqSum(arrays, middle + 1, right);
        int finalLeftSum = 0, thisLeftSum = 0;
        for (int i = left; i <=middle; i++) {
            thisLeftSum += arrays[i];
            if (thisLeftSum > finalLeftSum)finalLeftSum = thisLeftSum;
        }
        int finalRightSum = 0, thisRightSum = 0;
        for (int j = middle + 1; j < right; j++) {
            thisRightSum += arrays[j];
            if (thisRightSum > finalRightSum)finalRightSum = thisRightSum;
        }
        sum = finalLeftSum + finalRightSum;
        printf("left sum is %d,right sum is %d\n",finalLeftSum,finalRightSum);
        if (sum < leftSum)sum = leftSum;
        if (sum < rightSum)sum = rightSum;
    }
    return sum;
}
測試主函數
int main() {
    int array[] ={1,6,-5,4,2,-3,6};
    int result = MaxSubSeqSum(array,0,7);
    printf("result is %d\n", result);
}
運行結果

爲了方便觀察,咱們將每次左右兩邊求得的最大子序列最大和都打印出來面試

F:\ClionProject\DataStruct\cmake-build-debug\DataStruct.exe
left sum is 1,right sum is 6
left sum is 0,right sum is 4
left sum is 7,right sum is 0
left sum is 2,right sum is 0
left sum is 6,right sum is 0
left sum is 0,right sum is 6
left sum is 6,right sum is 5
result is 11

Process finished with exit code 0

線性表是最基本、最簡單、也是最經常使用的一種數據結構。
線性表中數據元素之間的關係是一對一的關係,即除了第一個和最後一個數據元素以外,其它數據元素都是首尾相接的(注意,這句話只適用大部分線性表,而不是所有。好比,循環鏈表邏輯層次上也是一種線性表(存儲層次上屬於鏈式存儲),可是把最後一個數據元素的尾指針指向了首位結點)。算法

線性表的兩種存儲方式數組

  • 順序存儲
  • 鏈式存儲
線性表的順序存儲
typedef struct LinkedList{
    int data[MAXSIZE];//存儲數組
    int Last;//遊標指針
}List;
List * MakeEmpty(){
    List *Ptrl;
    Ptrl=(List *)malloc(sizeof(List));
    Ptrl->Last=-1;
    return Ptrl;
}
/**T(n)=O(N)*/
int FindElement(int result,List* Ptrl){
    int i=0;
    while(i<=Ptrl->Last&&Ptrl->data[i]!=result)
        i++;
    if(i>Ptrl->Last)return -1;//若是沒有找到返回-1
    else return i;
}
void Insert(int result,int i,List *Ptrl){
    int j;
    if(Ptrl->Last==MAXSIZE-1){
        printf("表滿");
        return;
    }
    if(i<1||i>Ptrl->Last+2){
        printf("插入位置不合法");
        return;
    }
    for(j=Ptrl->Last;j>=i-1;j--)//倒序移動(注意j>=i-1)
        Ptrl->data[j+1]=Ptrl->data[j];
    Ptrl->data[i]=result;//插入數據
    Ptrl->Last++;//Last指針++
    return;
}
/*T(N)=O(N)*/
void DeleteElement(int i,List* Ptrl){
    int j;
    if(i<1||i>Ptrl->Last+1){//判斷位置的合法性(注:鏈表下標是從1開始的)
        printf("第%d個元素不存在",i);
        return;
    }
    for(j=i;j<=Ptrl->Last;j++)//全部元素前移
        Ptrl->data[j-1]=Ptrl->data[j];
    Ptrl->Last--;
    return;
}

線性表的鏈式存儲

typedef struct LinkedList {
    int data;
    struct LinkedList *next;
} List;

//求鏈表長度
int Length(List *Ptrl) {
    List *p = Ptrl;
    int j = 0;
    while (p) {
        p = p->next;
        j++;
    }
    return j;
}

//按序號查找
List *FindKth(int k, List *Ptrl) {
    List *p = Ptrl;//不改變頭節點,返回移動指針p
    int i = 1;
    while (p != NULL && i < k) {
        p = p->next;
        i++;
    }
    if (i == k)return p;
    else return NULL;
}

//按值查找
List *Find(int result, List *Ptrl) {
    List *p = Ptrl;
    while (p != NULL && p->data != result)
        p = p->next;
    return p;
}

//構造新的結點,申請空間
//找到鏈表的低i-1個結點
//修改指針插入結點
List *Insert(int result, int i, List *Ptrl) {
    List *p, *s;
    if (i == 1) {//判斷鏈表爲空的時候
        s = (List *) malloc(sizeof(List));
        s->data = result;
        s->next = Ptrl;
        return s;
    }
    p = FindKth(i - 1, Ptrl);//查找第i-1個節點
    if (p == NULL) {
        printf("參數錯誤");
        return NULL;
    } else {
        s = (List *) malloc(sizeof(List));
        s->data = result;
        s->next = p->next;
        p->next = s;
        return Ptrl;
    }
}

List *Delete(int i, List *Ptrl) {
    List *p, *s;
    if (i == 1) {//檢查要刪除的是否是第一個結點
        s = Ptrl;//s指向第一個結點
        if (Ptrl != NULL)Ptrl = Ptrl->next;//從鏈表中刪除
        else return NULL;
        free(s);//釋放空間
        return Ptrl;
    }
    p = FindKth(i, Ptrl);
    if (p == NULL) {//後項前移
        printf("輸入錯誤");
        return NULL;
    } else if (p->next != NULL) {
        s=p->next;
        p->next = s->next;
        free(s);//清理無用空間
        return Ptrl;
    }
}
堆棧(順序存儲)數組方式
typedef struct{
    int Data[MAXSIZE];
    int Top;
}Stack;
void Push(Stack *stack,int value){
    if(stack->Top==MAXSIZE-1){//數組有界
        printf("堆棧滿");
    }else{
        stack->Data[++(stack->Top)]=value;
        return;
    }
}
int Pop(Stack *stack){
    if(stack->Top==-1){//爲空檢查
        printf("堆棧爲空");
        return ERROR;
    } else
    return stack->Data[stack->Top--];
}
一個有界數組存儲兩個堆棧
#define MAXSIZE 50
   /*一個有界數組存儲兩個堆棧,若是數組有空間則執行入棧操做,(一個向右增加,一個向左增加)
    * */
   typedef struct DStack{
       int data[MAXSIZE];
       int Top1;
       int Top2;
   }Stacks;
   void Push(Stacks *stacks,int value,int Tag){
       if(stacks->Top2-stacks->Top1==1){
           printf("堆棧滿");return;
       }
       if(Tag==1)
           stacks->data[++stacks->Top1]=value;
       else
           stacks->data[--stacks->Top2]=value;
   }
   int Pop(Stacks *stacks,int Tag){
       if(Tag==1){
           if(stacks->Top1==-1){
               printf("堆棧1空");
               return NULL;
           }else {
               return stacks->data[stacks->Top1--];
           }
       }else{
           if(stacks->Top2==MAXSIZE){
               printf("堆棧2空");
               return NULL;
           }else{
               return stacks->data[stacks->Top2++];
           }
       }
   }
   int main() {
       Stacks *stacks;
       stacks->Top1=-1;
       stacks->Top2=MAXSIZE;//初始化兩個堆棧頭指針
       return 0;
   }

堆棧(鏈式存儲)

/*用單向鏈表表示棧時候,棧Top結點必定是鏈頭結點
 * */
typedef struct Node{
    int value;
    struct Node *next;
}LinkedStack;
LinkedStack * CreateLinkedStack(){
    LinkedStack *stack;
    stack=(LinkedStack *)malloc(sizeof(LinkedStack));
    stack->next=NULL;
    return stack;
};
int isEmpty(LinkedStack *stack){//注意Top結點沒有值,只有一個單鏈表的頭指針
    return (stack->next==NULL);
}
void Push(LinkedStack *stack,int value){
    LinkedStack *insertElement;
    insertElement=malloc(sizeof(LinkedStack));//分配內存空間
    insertElement->value=value;//插入的值賦值給結點
    insertElement->next=stack->next;//將已存在鏈表連接到插入的結點
    stack->next=insertElement;//改變Top結點
}
int Pop(LinkedStack *stack){
    int result;
    LinkedStack *popElement;
    if(isEmpty(stack)){
        printf("鏈表爲空");
        return ERROR;
    }else{
        popElement=stack->next;
        result=popElement->value;
        stack->next=popElement->next;
        free(popElement);//記得釋放無用內存空間
        return result;
    }
}

中綴表達式如何轉換爲後綴表達式
從頭至尾讀取中綴表達式的每個對象數據結構

  • 1.運算數:直接輸出
  • 2.左括號:壓入堆棧
  • 3.右括號:將棧頂的運算符彈出並輸出,直到遇到左括號(出棧不輸出)
  • 4.運算符:
    若優先級大於棧頂運算符,則壓棧
    若優先級小於等於棧頂運算符,將棧頂運算符彈出,

再比較新的棧頂運算符,直到改運算符大於棧頂運算符優先級爲止,而後壓棧app

  • 5.若個對象處理完畢,則把堆棧中存留的運算符一併輸出

堆棧用途:ide

  • 函數調用及遞歸實現
  • 深度優先搜索
  • 回溯算法
隊列(順序存儲)
#define MAXSIZE 50
typedef struct {
    int value[MAXSIZE];
    int rear;
    int front;
}Queue;
Queue *CreateQueue(){
    Queue *queue;
    queue=(Queue *)malloc(sizeof(Queue));
    queue->front=0;
    queue->rear=0;
    return queue;
}
void AddQueue(Queue *queue,int value){
    if((queue->rear+1)%MAXSIZE==queue->front){
        printf("queue is full");
        return;
    }else {
        queue->rear=(queue->rear+1)%MAXSIZE;
        queue->value[queue->rear] = value;
    }
}
int IsEmpty(Queue *queue){
    if(queue->rear==queue->front)return 1;
    else return 0;
}
void OutQueue(Queue* queue,int *value){
    if(IsEmpty(queue)){
        printf("Queue is empty");
        return;
    }else{
        queue->front=(queue->front+1)%MAXSIZE;
        *value=queue->value[queue->front];
    }
}

隊列(鏈式存儲)注意

typedef struct Node {
    int value;
    struct Node *next;
} QNode;
typedef struct {
    QNode *rear;
    QNode *front;
} Queue;

void InitQueue(Queue **queue) {
    QNode *p;
    p = (QNode *) malloc(sizeof(QNode));
    p->next = NULL;
    (*queue)->front = p;
    (*queue)->rear = p;
}

void InQueue(Queue *queue, int value) {
    QNode *InElement;
    InElement = (QNode *) malloc(sizeof(QNode));
    InElement->value = value;
    InElement->next = NULL;
    queue->rear->next = InElement;
    queue->rear = InElement;
}

int IsEmpty(Queue *queue) {
    if (queue->rear = queue->front)return 1;
    else return 0;
}

void OutQueue(Queue *queue, int *value) {
    QNode *OutElement;
    if (IsEmpty(queue)) {
        printf("queue is empty");
        return;
    } else {
        OutElement = queue->front->next;
        queue->front->next=OutElement->next;//指針頭結點指向下一個結點(pspspspsps)
        *value=OutElement->value;
        free(OutElement);
        if(IsEmpty(queue)){//出隊列後若是隊列爲空則置爲空隊列
            queue->front=queue->rear;
        }
    }
}

斷定樹

每一個結點須要查找的次數恰好爲該結點所在的層數,查找成功時查找次數不會超過斷定樹的深度,n個結點的斷定樹的深度爲[LgN]+1函數

平均查找長度ASL(Average Search Length)
ASL=sum(層數*個數)/各層總個數n(n>=0)個結點構成的有限集合當n=0時稱爲空樹oop

對於任何一棵非空樹(n>0),它具有如下性質測試

  • 樹中會有一個root特殊結點用r表示
  • 其他結點可分爲m(m>0)個互不相交的有限集,其中每一個集合自己又是一棵樹,稱爲原來樹的子樹

樹的特色:

  • 子樹是不相交的
  • 出了根節點外,每隔結點有且僅有一個父結點
  • 一棵N個結點的樹有N-1條邊(樹是保證結點連通的最少邊連接方式)

樹的一些基本術語:

  • 結點的度:結點的子樹個數(滿二叉樹單個結點的度爲2)
  • 樹的度:樹的全部結點中最大的度數
  • 葉結點:結點度爲0的結點
  • 父節點,子節點,兄弟結點
  • 路徑和路徑長度
  • 祖先節點:沿樹根到某一結點路徑上的全部節點都是這個結點的祖先結點
    子孫結點通;
  • 結點的層次:規定根結點在一層,其餘層次隨子節點+1
  • 樹的深度:樹中結點的最大層次就是這棵樹的深度

    兒子兄弟表示法能夠將全部的樹轉化爲二叉樹

特殊二叉樹:

  • 斜二叉樹:只有左兒子或只有右結點
  • 完美二叉樹:滿二叉樹
  • 徹底二叉樹:結點編號與滿二叉樹結點編號相同(編號不間斷)

二叉樹的特色

  • 一個二叉樹第i層的最大節點數爲:2(i-1),i>=1
  • 深度爲k的二叉樹有最大節點總數爲2k-1,k>=1;
  • 對於任何非空二叉樹T,若N0表示葉子結點的個數,N2是度爲2的非葉結點個數,那麼二者知足關係:N0=N2+1;(即葉子結點個數-1=度數爲2的結點個數)

二叉樹的抽象數據類型定義
數據對象集:一個有窮的結點集合
若不爲空,則由根節點和其左、右二叉樹組成
操做集:判斷樹是否爲空,遍歷,建立二叉樹

經常使用的遍歷方法有:
先序遍歷(根左右),
中序遍歷(左根右),
後序遍歷(左右根),
層次遍歷(從上到下,從左到右)

在二叉樹中,咱們知道葉結點總數n0與有兩個兒子的結點總數n2之間的關係是:n0=n2+1.
那麼相似關係是否能夠推廣到m叉樹中?也就是,若是在m叉樹中,葉結點總數是n0,
有一個兒子的結點總數是n1,有2個兒子的結點總數是n2,有3個兒子的結點總數是n3,
那麼,ni之間存在什麼關係?

  • 徹底二叉樹,非根節點的父節點序號是[i/2]
  • 結點的左孩子結點序號是2i,若2i<=n,不然沒有左孩子結點
  • 結點的右孩子結點序號是2i+1,(若2i+1<=n,不然沒有右孩子)
typedef struct BT{
     int value;
     struct BT *leftchild;
     struct BT *rightchild;
 }BinTree;
 //二叉樹的每一個結點遍歷都會遇到三次,第一次遇到就打印的爲先序遍歷,第二次遇到就打印的爲中序遍歷,第三次遇到就打印的爲後序遍歷
 //先序遍歷(遞歸遍歷)
 void PreOrderTraversal(BinTree *BT){
     if(BT){
     if(!BT->leftchild&&!BT->rightchild)
         printf("%d\n",BT->value);
         PreOrderTraversal(BT->leftchild);
         PreOrderTraversal(BT->rightchild);
     }
 }
 //中序遍歷(遞歸遍歷)
 void InOrderTraversal(BinTree *BT){
     if(BT){
     if(!BT->leftchild&&!BT->rightchild)
         InOrderTraversal(BT->leftchild);
         printf("%d\n",BT->value);
         InOrderTraversal(BT->rightchild);
     }
 }
 //後序遍歷(遞歸遍歷)
 void PostOrderTraversal(BinTree *BT){
     if(BT){
     if(!BT->leftchild&&!BT->rightchild)
         PostOrderTraversal(BT->leftchild);
         PostOrderTraversal(BT->rightchild);
         printf("%d\n",BT->value);
     }
 }
 //二叉樹遍歷的本質是將二維序列轉換爲一維序列
 //使用隊列進行二叉樹的層級訪問(遍歷根節點,將左右兒子節點入隊列)
 void LevelOrderTraversal(BinTree BT){
     Queue *queue;
     BinTree *T;
     queue=CreateQueue();
     AddQueue(queue,BT);
     while(!IsEmptyQueue(queue)){
         T=DeleteQueue(queue);
         printf("%d\n",T->value);
         if(T->leftchild)AddQueue(queue,T->leftchild);
         if(T->rightchild)AddQueue(queue,T->rightchild);
     }
 }
 //給定前中序遍歷結果或中後序遍歷結果能夠惟一肯定一棵二叉樹,給定先後序遍歷結果不能惟一肯定二叉樹
 //非遞歸實現(中序遍歷)
 void InOrderTraversal(BinTree *BT){
     BinTree *T=BT;
     LinkedStack *stack=CreateLinkedStack();//建立並初始化堆棧
     while(T||!isEmpty(stack)){
         while(T){//一直向左將沿途結點壓入堆棧
             Push(stack,T);
             T=T->leftchild;//轉向左子樹
         }
         if(!isEmpty(stack)){
             T=Pop(stack);//結點彈出堆棧
             printf("%5d",T->value);//打印結點
             T=T->rightchild;//轉向右子樹
         }
     }
 }
 //非遞歸實現(先序遍歷)
 void PreOrderTraversal(BinTree *BT){
     BinTree *T=BT;
     LinkedStack *stack=CreateLinkedStack();//建立並初始化堆棧
     while(T||!isEmpty(stack)){
         while(T){//一直向左將沿途結點壓入堆棧
             printf("%5d",T->value);//打印結點
             Push(stack,T);
             T=T->leftchild;//轉向左子樹
         }
         if(!isEmpty(stack)){
             T=Pop(stack);//結點彈出堆棧
             T=T->rightchild;//轉向右子樹
         }
     }
 }
二叉搜索樹:BST(binary search tree)

也稱二叉排序樹或二叉查找樹
二叉搜索樹條件

1.非空左子樹的全部鍵值小於其根節點的鍵值
   2.非空右子樹的全部鍵值大於其根節點的鍵值
   3.左,右子樹都是二叉搜索樹
//遞歸方式實現
Position Find(BinTree *binTree,int result){
    if(!binTree)return NULL;
    if(result>binTree->value)return Find(binTree->rightchild,result);
    else if(result<binTree->value)return Find(binTree,result);
    else return binTree;//查找成功,返回結點地址(return尾遞歸)
}
//非遞歸方式實現
Position IterFind(BinTree *binTree,int value){
    while(binTree){
        if(result>binTree->value)
            binTree=binTree->rightchild;
        else if(result<binTree->value)
            binTree=binTree->leftchild;
        else 
            return binTree;
    }
    return NULL;
}
//尋找最小值
Position FindMin(BinTree *binTree){
    if(!binTree)return NULL;
    else if(!binTree->leftchild)
        return binTree;
    else
        return FindMin(binTree->leftchild);
}
//尋找最大值
Position FindMax(BinTree *binTree){
    if(binTree){
        while(binTree->rightchild)
            binTree=binTree->rightchild;
    }
    return binTree;
}
//結點插入
BinTree * Insert(BinTree *binTree, int value) {
    if(!binTree){
        binTree=malloc(sizeof(BinTree));
        binTree->value=value;
        binTree->leftchild=binTree->rightchild=NULL;
    }else{
        if(value<binTree->value)
            binTree->leftchild=Insert(binTree->leftchild,value);
        else if(value>binTree->value)
            binTree->rightchild=Insert(binTree->rightchild,value);
    }
    return binTree;
}
//刪除結點
BinTree *Delete(BinTree *binTree,int value){
    (Position)BinTree *Temp;
    if(!binTree)printf("要刪除的元素未找到");
        //左子樹遞歸刪除
    else if(value<binTree->value)binTree->leftchild=Delete(binTree,value);
        //右子樹遞歸刪除
    else if(value>binTree->value)binTree->rightchild=Delete(binTree->rightchild,value);
    else //找到要刪除的結點
        if(binTree->leftchild&&binTree->rightchild){//被刪除結點有左右量子子節點
            Temp=FindMin(binTree->rightchild);//在右子樹中招最小的元素填充刪除結點
            binTree->value=Temp->value;
            binTree->rightchild=Delete(binTree->rightchild,binTree->value);
        }else{//被刪除的結點有一個或無子結點
            Temp=binTree;
            if(!binTree->leftchild)binTree=binTree->rightchild;
            else if(!binTree->rightchild)binTree=binTree->leftchild;
            free(Temp);
        }
    return binTree;
}
平衡二叉樹(Balanced Binary Tree)

(AVL樹)(AVL是提出平衡樹的學者名字首字母)

  • 空樹或任一結點左右子樹高度差不超不過1|BF(T)|<=1
  • 平衡因子(Balance Factor 簡稱BF:BF(T)=Hl-Hr)
  • 其中hl和hr分別爲T的左右子樹高度
  • 高度=層數-1
  • 徹底二叉樹高度爲log2N(平衡二叉樹)
  • Nh是高度爲h的平衡二叉樹的最小結點樹
  • Nh=F(h+2)-1
#define MaxData 10000
 typedef struct HeapStruct{
     int *value;//存儲對元素的數組
     int length;//堆的當前元素個數
     int capacity;//堆的最大容量
 }Heap;
優先隊列(PriorityQueue)

取出元素的前後順序是按照元素的優先權(關鍵字)大小,而不是元素進入隊列的前後順序
最大堆和最小堆都必須知足徹底二叉樹(切根節點最大或最小)最大堆的創建

創建最大堆:將已經存在的N個元素按最大堆的要求存放在要給一維數組中

  • 方法一:經過插入操做,將N個元素一個個相繼插入到一個初始爲空的堆中去,其時間代價最大爲O(NlogN)
  • 方法二:在線性時間複雜度下創建最大堆

    • (1)將N個元素按輸入順序存入,先知足徹底二叉樹的結構特性
    • (2)調整各結點位置以知足最大堆的有序特性
      建堆時,最壞的狀況下須要挪動的元素次數等於樹中各節點的高度和

對由一樣n個整數構成的二叉搜索樹(查找樹)和最小堆:有如下結論

  • 二叉搜索樹高度大於等於最小堆高度
  • 對該二叉搜索樹進行中序遍歷可獲得從小到大的序列
  • 從最小堆根節點到起任何葉結點的路徑上的結點值構成從小到大的序列
Heap * Create(int MaxSize){
     Heap *heap=malloc(sizeof(Heap));
     heap->value=malloc((MaxSize+1)*sizeof(int));
     heap->length=0;
     heap->capacity=MaxSize;
     heap->value[0]=MaxData;//定義哨兵,便於操做
     return heap;
 }
 void Insert(Heap *heap,int value){
     int i;
     if(IsFull(heap)){
         printf("最大堆已經滿了");
         return;
     }
     i=++heap->length;
     for(;heap->value[i/2]<value;i/=2)
         heap->value[i]=heap->value[i/2];
     heap->value[i]=value;
 }
 int DeleteMax(Heap *heap){
     int parent,child;
     int maxValue,temp;
     if(IsEmpty(heap)){
         printf("最大堆已空");
         return 0;
     }
     maxValue=heap->value[1];
     //用最大堆中最後一個元素從根節點開始過濾下層結點
     temp=heap->value[heap->length--];
     for(parent=1;parent*2<=heap->length;parent=child){
         child=parent*2;
         //左兒子和右兒子節點比較取較大者
         if((child!=heap->length)&&(heap->value[child]<heap->value[child+1]))
             child++;
         if(temp>=heap->value[child])break;
         else
             heap->value[parent]=heap->value[child];
     }
     heap->value[parent]=temp;
     return maxValue;
 }
 int IsEmpty(Heap *heap){
     return heap->length==0;
 }
 int IsFull(Heap *heap){
     return heap->length==heap->capacity;
 }
 
 typedef struct TreeNode{
     int weight;
     struct TreeNode *left,*right;
 }HuffmanTree;
哈夫曼樹(HuffmanTree)

查找效率,查找次數乘查找機率
帶權路徑長度(WPL):設二叉樹有n個葉子結點,每隔葉子結點帶有權值Wk,從根節點到每隔葉子結點的長度是Lk,則每隔葉子結點的帶全路徑長度之和WPL=(nEk=1)WkLk
最優二叉樹或哈夫曼樹:WPL最小的二叉樹
哈夫曼樹的特色

  • 沒有度爲1的結點
  • n個葉子結點的HuffmanTree有2n-1個結點
  • HuffmanTree的任意非葉結點的左右子樹交換後還是HuffmanTree
    對於一組權值,可能有不一樣構的兩棵HuffmanTree

    HuffmanTree *Huffman(Heap *heap){
        //假設heap->length權值已經存在heap->value[]->weight裏面
        int i;HuffmanTree *huffmanTree;
        BuildHeap(heap);//將heap->value[]按權值調整爲最小堆
        for(i=1;i<heap->length;i++){
            huffmanTree=malloc(sizeof(HuffmanTree));//創建新結點
            huffmanTree->left=DeleteMin(heap);//從最小堆中刪除一個結點,做爲新huffmanTree的左子結點
            huffmanTree->right=DeleteMin(heap);//從最小堆中刪除一個結點,做爲新huffmanTree的右子結點
            huffmanTree->weight=huffmanTree->weight+huffmanTree->right->weight;//計算新// 權值
            Insert(heap,huffmanTree);
        }
        huffmanTree=DeleteMin(heap);
        return huffmanTree;
    }
    /*二叉樹用於編碼
     * 當被編碼字母所有在二叉樹的葉子結點的時候(即,編碼字母不會出如今有子節點的結點中)即可以保證字符編碼沒有二義性
偶然在一本書上看到這樣一道題以爲聽一意思的就拿來作了一下,題目是這樣設置的
**在已知一維數組A[m+n]中一次存放兩個線性表(a1,a2,a3,a4...am),(b1,b2,b3...bn),試寫出一個函數將兩個順序表位置互換,即由`(a,1,a2,a3,a4...am,b1,b2,b3...bn)`轉換成`(b1,b2,b3...bn,a,1,a2,a3,a4...am)`要求空間複雜度爲O(1)**想必這種題會常常出如今面試題目中吧,哈哈,扯遠了,如下是個人答案,水平有限,若有紕漏還望各位大神不吝賜教。


乍一看題目還挺麻煩的,兩個數組大小不同,原地逆置循環次數不容易控制,換個思路從新整理一下發現能夠用一種很巧妙的方法分三步實現
第一步:將字母序列逆置
第二部:將數字序列逆置
第三部:將數組總體逆置
**其中逆置函數以下:**
逆置函數須要兩個參數,分別爲須要逆置的數組起始位置[start]和終止位置[end];
public static void reverse(int start,int end){//逆置函數
    char temp;
    while(start<end) {
        temp = array[start];
        array[start++] = array[end];
        array[end--] = temp;
    }
}
tip:*char array[]={'A','B','C','D','E','F','G','H','1','2','3','4'}*
測試數組A[0-7],B[8-11]

**測試結果以下:**
![image.png](http://upload-images.jianshu.io/upload_images/2480310-05c78f4d0acc3395.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/640)


### 完整代碼

public class Main {

public static char array[]={'A','B','C','D','E','F','G','H','1','2','3','4'};
public static void main(String[] args) {
    reverse(0,7);//逆置字母序列結果爲:HGFEDCBA1234
    reverse(8,11);//逆置數字序列結果爲:HGFEDCBA4321
    reverse(0,11);//總體逆置結果爲:1234ABCDEFG
    print(array);
}
public static void reverse(int start,int end){//逆置函數
    char temp;
    while(start<end) {
        temp = array[start];
        array[start++] = array[end];
        array[end--] = temp;
    }
}
private static void print(char[] array) {
    for (int i = 0; i <array.length; i++)
        System.out.print(array[i]);
    System.out.println();
}

}

### N皇后問題

/**

  • n queens problem

*

  • */

public class EightQueen {

private int QUEEN_COUNT = 0;//represent the queen count
private int[][] queenCount;//chess box matrix
private int resultCount = 0;//solution number
private int[] queenPlace;//mark the queen placed position
/**
 * construct a EightQueen with a argument represent the number of queen
 * initial a empty chess box
 * 0 represent empty
 * 1 represent the area has been taken
 * recurse to call the putQueen method
 * the queenPlace array to mark the queen's taken area which uses to print
 *
 * */
public EightQueen(int n) {
    this.QUEEN_COUNT = n;
    this.resultCount = 0;
    this.queenCount = new int[QUEEN_COUNT][QUEEN_COUNT];
    queenPlace = new int[QUEEN_COUNT];
    putQueen(0);
}
/**
 * implement the putQueen function to recursion
 * use column index in outer loop and row index in inner loop with step increase
 * */
private void putQueen(int row) {
    for (int column = 0; column < QUEEN_COUNT; column++) {//loop for QUEEN_COUNT times
        if (queenCount[row][column] == 0) {//judge the condition
            /**
             * each row has one queen
             * mark the column and diagonal back diagonal(row has been scatter)
             *
             * */
            for (int nextRow = row + 1; nextRow < QUEEN_COUNT; nextRow++) {
                queenCount[nextRow][column]++;
                if (column - nextRow + row >= 0) {
                    queenCount[nextRow][column - nextRow + row]++;
                }
                if (column + nextRow - row < QUEEN_COUNT) {
                    queenCount[nextRow][column + nextRow - row]++;
                }
            }
            queenPlace[row] = column;//place the queen with only column information
            if (row == QUEEN_COUNT - 1) printQueen(++resultCount);//recursion has completed
            else putQueen(row + 1);//recurse to call the putQueen function
            /**
             *
             * unmarked the column and diagonal back diagonal(row has been scatter)
             *
             * */
            for (int rows = row + 1; rows < QUEEN_COUNT; rows++) {
                queenCount[rows][column]--;
                if (column - rows + row >= 0) {
                    queenCount[rows][column - rows + row]--;
                }
                if (column + rows - row < QUEEN_COUNT) {
                    queenCount[rows][column + rows - row]--;
                }
            }
        }
    }
    if (row == 0) System.out.println(QUEEN_COUNT + " queens has totally " + resultCount + "result.");
}

private void printQueen(int size)
{
    System.out.println("********** "+size+" **********\n");
    for (int i = 0; i < QUEEN_COUNT; i++) {
        for (int j = 0; j < QUEEN_COUNT; j++) {
            System.out.print(queenPlace[i] == j ? " # " : " - ");
        }
        System.out.println();
    }
}

}

### 優先隊列

/**

  • use maximum-top heap to implement priority queue
  • define a MAX_SIZE_OF_PRIORITY_QUEUE to limit the max length of priority queue
  • use a integer array to store element
  • hypothesis i is the root node and then use 2i to mark left child and 2i+1 to mark right child
  • use initialArray[0] to store the length of heap
  • */

public class PriorityQueue{

private static final int MAX_SIZE_OF_PRIORITY_QUEUE=100;
private int[] initialArray;
/**
 * initial priority queue with a exist array which can't be null
 * */
public PriorityQueue(int[] initialElement) {
    if(initialElement==null)return;
    if(initialElement.length==0)return;
    initialArray=new int[MAX_SIZE_OF_PRIORITY_QUEUE];
    initialArray[0]=initialElement.length;
    for(int i=0;i<initialElement.length;i++)initialArray[i+1]=initialElement[i];
    System.out.println(initialArray[0]);
    for (int i = initialArray[0]; i >0 ; i--)reBuildHeap(i);
}
/**
 * rebuild array according to the value of each node
 * maximum-top heap
 * index represents the index of a node which should be rebuild(include it's children node)
 *
 * simple:
 *         1
 *      2     3
 *   4   5  6   7
 *
 * */
private void reBuildHeap(int index){
    System.out.println("execute rebuild function to rebuild a maximum-top heap with one loop");
    int leftChildIndex=index*2;
    int rightChildIndex=leftChildIndex+1;
    int length=initialArray[0];
    int biggerValueIndex=-1;
    if(leftChildIndex>length&&rightChildIndex>length){
        System.out.println("no left child");
        return;
    }
    if(leftChildIndex<=length&&rightChildIndex>length){
        System.out.println("only left child");
        biggerValueIndex=leftChildIndex;
    }
    if(leftChildIndex>length&&rightChildIndex<=length){
        System.out.println("only right child");
        biggerValueIndex=rightChildIndex;
    }
    if(leftChildIndex<=length&&rightChildIndex<=length){
        System.out.println("both children");
        biggerValueIndex=initialArray[leftChildIndex]>initialArray[rightChildIndex]?leftChildIndex:rightChildIndex;
    }
    if(initialArray[index]>initialArray[biggerValueIndex]){
        System.out.println("unnecessary to swap!");
        return;
    }else{
        int temp=initialArray[index];
        initialArray[index]=initialArray[biggerValueIndex];
        initialArray[biggerValueIndex]=temp;
        this.reBuildHeap(biggerValueIndex);
    }
}
public int getLength() {
    return initialArray[0];
}
/**
 * get top priority value of heap
 * the first element of array
 * */
public int priority(){
    return initialArray[1];
}
/**
 * length++
 * add element to the tail of array
 * rebuild the heap to regular priority heap
 * */
public void insert(int element){
    initialArray[0]++;
    initialArray[initialArray[0]]=element;
    for(int i=initialArray[0];i>=1;i=i/2){
        reBuildHeap(i);
    }
}
/**
 * length--
 * swap the first element and last element
 * delete last value
 * rebuild the heap
 * */
public int deletePriority(){
    if(initialArray[0]<=0)return -1;
    int maxValue=initialArray[1];
    initialArray[1]=initialArray[initialArray[0]];
    initialArray[0]--;
    for(int i=initialArray[0];i>=1;i=i/2){
        reBuildHeap(i);
    }
    return maxValue;
}
/**
 * print the structure of priority heap
 * */
@Override
public String toString() {
    StringBuilder builder=new StringBuilder("{");
    for (int i = 1; i <= initialArray[0]; i++) {
        if(i!=1)builder.append(",");
        builder.append(initialArray[i]);
    }
    builder.append("}");
    return builder.toString();
}

}

相關文章
相關標籤/搜索