歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C語言遞歸,非遞歸實現翻轉鏈表

C語言遞歸,非遞歸實現翻轉鏈表

日期:2017/3/1 9:16:19   编辑:Linux編程

翻轉鏈表作為,鏈表的常用操作,也是面試常遇到的。

分析
非遞歸分析:

非遞歸用的小技巧比較多,很容易出錯。

遞歸分析比較簡單,在代碼裡面

代碼:

#include<stdio.h>
#include<stdlib.h>
typedef int elemtype;
typedef struct node{
    elemtype element;
    struct node*next;//寫成node* next;node * next;node *next;也是可以的,為了方便閱讀,以後統一寫成elemtype* element。'*',';',',''=','->'等等這些特殊意義的關鍵字符語法規則差不多,本身具有分割意義,兩旁加空格與不加空格的意義是一致的,也就是說空格對這些特殊字符是不起作用的,而解析編譯器,運行器也不是利用空格來分割的;標志符是不能用這些字符,為了方便閱讀,不會看的一駝屎,最好在這些特殊的字符兩旁加空格。
}node;//這個類型名與其的結構體名可以一樣,不矛盾。

/*Function:將鏈表所有結點從頭結點順序打印,遍歷鏈表。traverse_linkedList
 *遍歷一種數據機構,進去看一看,給人說一說,一般遍歷打印裡面的數據,知道是進去,可以拿到裡面的數據。
 *這種數據結構有很多數據元素,但每次遍歷只能訪問一個元素,因此要循環,而且要訪問所有的結點,必須有一種機制從一個結點跳到另一個結點。
 *@paramb:node* phead :鏈表首地址,首結點地址。
 */
void traverse_linkedList(node* phead){
    node *p=phead ;//定義一個跳轉控制指針
    if (NULL == p){
        printf("親,鏈表為空\n");
        return ;
    }
    else{
        while(NULL !=  p){

        printf("%d\n",p -> element);//訪問結構體的數據,可以用: 其結構體變量.成員變量;還可以:指向這個結構體的指針 -> 成員變量
        p = p -> next ;
        }    
    }

}
/*Function:翻轉鏈表(非遞歸) reverse_linkedList
 *param:node** phead  //參數意義:保存鏈表指針變量的地址
 *return: void
 *
 *知識點:node** p;p代表鏈表指針變量的地址。*p才是鏈表。**p 代表結點(可以認為"*"具有解析功能)
 *整體的思路:重整結點的關系,原來從左指向右,翻轉後從右指向左;原來指向頭結點,翻轉後指向尾結點
 *
 *時間復雜度:O(n)
 *
 *
 * */
void reverse_linkedList(node** phead){//存鏈表頭的指針變量的地址傳過來,旨在能改變這個變量,指針本質上是存地址的變量。
    node *pLeft,*pRight,*pMiddle;//定義三個指針: 左中右,pRight:作移動。
    pLeft=pRight=*phead;
    //空鏈表或者只有一個結點
    if(NULL == pLeft || NULL == ( pLeft -> next)){
            return ;
    
    }else{
        //頭的結點的處理
        pLeft = *phead ;
            pRight = (*phead) -> next ; //' ->'優先級最高
        pLeft -> next = NULL ;

        //循環控制條件    
            node *ctl=pRight;
         while(NULL != ctl){
            pMiddle = pRight ;// 在移動前,先保存
            pRight = pRight -> next ;// pRight移動到下一個結點
            ctl = pMiddle -> next; //在變換關系前,先把控制的信息存起來 
            pMiddle -> next = pLeft ; //變換關系
            pLeft = pMiddle ; // p變換    
        }
        
        *phead = pLeft ; //指向鏈表頭指針變量,指向新的頭。
    }
}
/*
 *Function:翻轉鏈表(遞歸) reverse_recursive_linkedList
 *param:node* head  
 *return: node*
 *
 *知識點:
 *遞歸:自身調用自身;出口。
 *思考:
 *
 *如果鏈表是空鏈表或者只有一個結點,就可以直接的返回表頭;如果是兩個結點以上鏈表,調用自身,拿到子結點的表頭,再重建他們的關系。
 *
 * */
node* reverse_recursive_linkedList(node * head){
    if(head == NULL || head -> next == NULL){
       return head ; 
    }
    else{
       node* second = head -> next ;
       node* new_head = reverse_recursive_linkedList(second);
       second -> next = head ;
       head -> next = NULL ;
       return new_head ;       
    } 
}
int main()
{
    node *p , *q , *head;//僅僅定義了幾個指針變量,系統做了哪些工作呢?開辟這些指針變量類型所需的空間。若沒有初始值一般由系統隨機分配值,還沒有指向真正的結點,也就是說 p -> 成員變量是沒有意義的。會報""; node 類型的聲明,告訴系統作對應的語法檢查,該怎麼處理指針指向的內容。
    // insert 10 nodes
    //創建結點,結點本質上是數據塊,這些數據是占用空間的,有了儲存空間,就有了數據載體。所以開辟空間是創建數據的關鍵,然後告訴系統你怎麼來處理這塊空間,最後空間開辟成功。
    p = q = (node* )malloc(sizeof(node)) ;//與” 數據類型 標識符“ 創建的差別,無標識符,要手動開空間,並提取信息。標識符功能:解析+地址。
    head = p ;
    p -> element = 0 ;
    int i=0;
    for ( i = 0 ;i < 9 ; i++){
        
        q = (node* )malloc(sizeof(node)) ;
        q -> element = i + 1 ;
        p -> next = q ;
        p = q ;


    }
    

    traverse_linkedList(head);
    reverse_linkedList(&head);//&只能作取址用,沒有解析功能。
    traverse_linkedList(head);
    traverse_linkedList(reverse_recursive_linkedList(head));
}

本人在重拾C,很多東西看是熟悉而又陌生,所以注釋比較多一點,僅供參考,不爽直接忽略,

Copyright © Linux教程網 All Rights Reserved