【2015/11/21】 數據結構學習日誌_Day17 雙端鏈表

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hsgwpj/article/details/50045843
/*************************************************************************
    > File Name: ctr_list.c
    > Author: khalil
    > Mail: [email protected]
    > Created Time: Sat 21 Nov 2015 09:11:34 AM CST
 ************************************************************************/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

// 《C語言接口與實現》 *
//  C的面向對象: lua
//  redis 鍵值對數據庫

//比較優秀的網站:
//    stackoverflow
//    sourceforge

#if 1
//爲bool類型宏定義
#define true     (1)
#define false    (0)

#define ZERO     (0)
#define ONLY_ONE (1)
#define TWO      (2)
#define get_data_size()  ((unsigned long)&(((List_node *)0)->next))

//鏈表控制信息:
//
// 1.頭、尾節點位置
// 2.鏈表元素數量
//
//鏈表節點信息:
//
// 1.數據域
// 2.指針域

//節點:
typedef struct List_node
{
    int               data;     //數據域
    struct List_node *next;     //指針域
}List_node;

//控制:
typedef struct List
{
    struct List_node *head;     //指向鏈表頭部
    struct List_node *tail;     //指向鏈表尾部
    int              count;     //鏈表節點數量
}List;

typedef unsigned char bool;

static void *Malloc(size_t size); //包裹函數
static List_node *create_node(void);//創建節點
static void swap(void *a, void *b, int len);//交換data
static void reverse_show_list_node(List_node *p);//組件

static void swap(void *a, void *b, int len)
{
    void *tmp = Malloc(len);
    memcpy(tmp, a, len);
    memcpy(a, b, len);
    memcpy(b, tmp, len);

    free(tmp);
}
static List_node *create_node(void)
{
    List_node *node = (List_node *)Malloc(sizeof(List_node));
    bzero(node, sizeof(List_node));
    return node;
}

static void *Malloc(size_t size)
{
    void *result = malloc(size);
    if(result == NULL){
        fprintf(stderr, "Memory Full!\n");
        exit(1);
    }
    return result;
}

static void reverse_show_list_node(List_node *p)
{
    if(p){
        reverse_show_list_node(p->next);
        printf("%d\t", p->data);
    }
}

//鏈表接口:
List        *init_list(void);                       //鏈表的初始化
void        destory_list(List **);                  //鏈表的銷燬
bool        push_front(List *list, int value);      //頭部插入
bool        push_back (List *list, int value);      //尾部插入
bool        pop_front (List *list);                 //頭部刪除
bool        pop_back  (List *list);                 //尾部刪除
void        show_list (List *list);                 //顯示鏈表信息
void        sort_list_ascend (List *list);          //升序排列
void        sort_list_descend(List *list);          //降序排列
int         get_list_count   (List *list);          //得到鏈表節點數量

//進階

List        *merge_two_lists       (List *list1, List *list2);  //合併兩個有序鏈表
List        *merge_two_lists_recure(List *list1, List *list2);  //合併兩個有序鏈表(遞歸)
List_node   *find_revise_node(List *list, int num);             //找到鏈表的倒數第num個節點
List_node   *find_mid_node   (List *list);                      //找到鏈表的中間節點
List        *reverse_list    (List *list);                      //逆置一個鏈表
List        *list_dump       (List *list);                      //鏈表拷貝
void        reverse_show_list(List *list);                      //逆序輸出一個鏈表
bool        is_lists_intersect    (List *list1, List *list2);   //判斷鏈表是否相交
List_node   *get_first_common_node(List *list1, List *list2);   //得到第一個交點
void        delete_one_node       (List *List, List_node *node);//在O(1)的時間複雜度下刪除節點
bool        has_circle            (List *list, List_node **intersect);                 //判斷一個鏈表是否有環
List_node   *find_circle_first_node(List *list);                //找到帶環鏈表的環入口點

////////////////////////////////////////////////////////////
//////////////////////  接口實現  //////////////////////////
////////////////////////////////////////////////////////////

List        *init_list(void)                        //鏈表的初始化
{
    List *list = (List *)Malloc(sizeof(List));
    //    head && tail && count --> NULL/0
    bzero(list, sizeof(List));
    return list;
}

void        destory_list(List **list)                   //鏈表的銷燬
{
    if(list == NULL || *list == NULL){
        return;
    }
    //遍歷釋放空間
        //List *p_list = *list;
        //List_node *p_node = p_list->head;
        //List_node *q_node = NULL;
        //刪除鏈表節點信息
        //while(p_node){
        //    q_node = p_node;
        //    p_node = p_node->next;
        //    free(q_node);
        //}

    //刪除鏈表節點信息
    while((*list)->count){
        pop_front(*list);
    }
    //刪除鏈表控制信息
    free(*list);
    *list = NULL;
}

bool        push_front(List *list, int value)       //頭部插入
{
    if(list == NULL){
        return false;
    }

    //創建節點並賦值
    List_node *node = create_node();
    node->data = value;

    if(list->count == ZERO){

        //  case 1:空鏈表
        //  head && tail -> node_1; count = 1

        list->head = list->tail = node;
    }else{

        // case 2:非空鏈表
        // head -> node_1 ; tail -> node_n; count = n + 1

        node->next = list->head;
        list->head = node;
    }
    list->count++;
    return true;
}

bool        push_back (List *list, int value)       //尾部插入
{
    if(list == NULL){
        return false;
    }

    List_node *node = create_node();
    node->data = value;

    if(list->count == ZERO){
        //case 1: 空鏈表
        list->head = list->tail = node;
    }else{
        //case 2: 非空鏈表
        list->tail->next = node;
        list->tail = node;
    }
    list->count++;
    return true;
}

bool        pop_front (List *list)                  //頭部刪除
{
    if(list == NULL || list->count == ZERO){
        return false;
    }

    List_node *p_node = list->head;

    //case 1:只有一個節點
    //case 2:大於一個節點

    if(list->count == ONLY_ONE){
        list->head = list->tail = NULL;
    }else{
        list->head = list->head->next;
    }
    free(p_node);
    list->count--;
    return true;
}

bool        pop_back  (List *list)                  //尾部刪除
{
    if(list == NULL || list->count == ZERO){
        return false;
    }

    List_node *p_node = list->head;

    //case 1:只有一個節點
    //case 2:大於一個節點

    if(list->count == ONLY_ONE){
        list->head = list->tail = NULL;
        free(p_node);
    }else{
        //遍歷一遍鏈表 將p_node指向倒數第二個節點
        while(p_node->next != list->tail){
            p_node = p_node->next;
        }
        free(list->tail);
        list->tail = p_node;
        p_node->next = NULL;
    }
    list->count--;
    return true;
}

void        show_list (List *list)                  //顯示鏈表信息
{
    if(list != NULL && list->count != ZERO){
        List_node *p_node = list->head;
        for( ; p_node; p_node = p_node->next ){
            printf("%d\t",p_node->data);
        }
        printf("\n");
    }
}

void        sort_list_ascend (List *list)           //升序排列
{
    if(list == NULL || list->count < TWO){
        return ;
    }

    List_node *p_node = NULL;
    List_node *q_node = NULL;

    unsigned long data_size = 0;
    data_size = get_data_size();//求數據區域大小

    for(p_node = list->head; p_node->next; p_node = p_node->next){
        for(q_node = p_node->next; q_node; q_node = q_node->next){
            if(p_node->data > q_node->data){
                swap(p_node, q_node, data_size);
            }
        }
    }
}

void        sort_list_descend(List *list)           //降序排列
{
    if(list == NULL || list->count < TWO){
        return ;
    }

    List_node *p_node = NULL;
    List_node *q_node = NULL;

    unsigned long data_size = 0;
    data_size = get_data_size();//求數據區域大小

    for(p_node = list->head; p_node->next; p_node = p_node->next){
        for(q_node = p_node->next; q_node; q_node = q_node->next){
            if(p_node->data < q_node->data){
                swap(p_node, q_node, data_size);
            }
        }
    }
}

int         get_list_count   (List *list)           //得到鏈表節點數量
{
    if(list == NULL){
        return -1;
    }

    return list->count;
}

List        *merge_two_lists       (List *list1, List *list2)   //合併兩個有序鏈表
{
    List *result = NULL;
    if(list1 == NULL || list2 == NULL){
        return result;
    }

    result = init_list();
    List_node *p = list1->head;
    List_node *q = list2->head;

    // 如果兩個鏈表都沒有遍歷完,則進行比較
    while(p && q){
        if(p->data < q->data){
            push_back(result, p->data);
            p = p->next;
        }else{
            push_back(result, q->data);
            q = q->next;
        }
    }

    //如果有一個比較完了,把另一個直接進行拷貝
    if(p == NULL){
        while(q){
            push_back(result, q->data);
            q = q->next;
        }
    }
    if(q == NULL){
        while(p){
            push_back(result, p->data);
            p = p->next;
        }
    }

    return result;
}

List        *merge_two_lists_recure(List *list1, List *list2)   //合併兩個有序鏈表(遞歸)
{
    //使用組件來進行遞歸輸出!
}

List_node   *find_revise_node(List *list, int num)             //找到鏈表的倒數第num個節點
{
    if(list == NULL || num <= 0 && num > list->count){
        return NULL;
    }

    List_node *p = list->head;
    int time = list->count - num;

    while(time--){
        p = p->next;
    }

    return p;
}

List_node   *find_mid_node   (List *list)                      //找到鏈表的中間節點
{
    // 1.快慢指針:
    //  一個一次走兩步 一個一次走一步
    //
    // 2.count/2找指針

    if(list == NULL){
        return NULL;
    }

#if 1
    List_node *p = list->head;
    List_node *q = p;

    while(p){
        p = p->next;
        if(p){
            p = p->next;
        }
        q = q->next;
    }

    return q;
#endif

#if 0
    List_node *p = list->head;
    int time = list->count >> 1;
    while(time--){
        p = p->next;
    }
    return p;
#endif
}

List        *reverse_list    (List *list)                     //逆置一個鏈表
{
    if(list == NULL || list->count < TWO){
        return list;
    }
#if 0
    //創建一個新的鏈表 與數組
    int datas[list->count];
    List_node *p = list->head;
    List *result = init_list();
    int i = 0;
    for( ; i < list->count; ++i ){
        datas[i] = p->data;
        p = p->next;
    }

    for( ; i; --i ){
        push_back(result, datas[i-1]);
    }
    return result;
#endif

#if 1
    //不創建新鏈表 使用三個指針進行賦值
    if(list->count == TWO){
        //如果只有兩個節點
        list->tail->next = list->head;
        list->head->next = NULL;
        return list;
    }

    List_node *p = list->head;
    List_node *q = p->next;
    List_node *r = q->next;
    p->next = NULL;

    do{
        q->next = p;
        p = q;
        q = r;
        r = r->next;
    }while(r);

    q->next = p;

    swap(&(list->head), &(list->tail), sizeof(List_node *));
    return list;
#endif
}

List        *list_dump       (List *list)                      //鏈表拷貝
{
    if(list == NULL){
        return NULL;
    }

    List *result = init_list();
    List_node *p = list->head;

    while(p){
        push_back(result, p->data);
        p = p->next;
    }

    return result;
}

void        reverse_show_list(List *list)                      //逆序輸出一個鏈表
{
    if(list == NULL){
        return;
    }
    //遞歸逆序輸出比較好
    reverse_show_list_node(list->head);
    //使用組件來輸出
}

bool        is_lists_intersect    (List *list1, List *list2)   //判斷鏈表是否相交
{
    if (list1 == NULL || list2 == NULL){
        return false;
    }

    return (list1->tail == list2->tail);
}

List_node   *get_first_common_node(List *list1, List *list2)   //得到第一個交點
{
    if(! is_lists_intersect(list1, list2)){
        return NULL;
    }

    int list1_len = list1->count;
    int list2_len = list2->count;
    int distance  = 0;

    List_node *p = list1->head;
    List_node *q = list2->head;

    //將始末差距移動到相同距離
    if(list1_len > list2_len){
        distance = list1_len - list2_len;
        while(distance--){
            p = p->next;
        }
    }else{
        distance = list2_len - list1_len;
        while(distance--){
            q = q->next;
        }
    }

    //依次對對應節點進行判斷是否相等,相等則爲第一個相交界點
    while(p != q){
        p = p->next;
        q = q->next;
    }

    return p;
}

void        delete_one_node       (List *list, List_node *node)//在O(1)的時間複雜度下刪除節點
{
    if(list == NULL || node == NULL){
        return ;
    }

    List_node *p = NULL;
    if(node != list->tail){
        //不是末尾
        p = node->next;
        node->data = p->data;
        node->next = p->next;
        free(p);
        list->count--;
    }else{
        //是末尾
        pop_back(list);
    }
}

bool        has_circle            (List *list, List_node **intersect)                 //判斷一個鏈表是否有環
{
    if(list ==NULL || list->count < TWO){
        return false;
    }
    //快慢指針跑環
    //如果有環的話兩者一定會相遇
    List_node *fast = list->head;
    List_node *slow = fast;

    do{
        fast = fast->next;
        fast = fast->next;
        slow = slow->next;
        if(fast == slow){
            if(intersect){
                //將相交節點賦值給intersect
                *intersect = fast;
            }
            return true;
        }
    }while(fast && fast->next);

    return false;
}

List_node   *find_circle_first_node(List *list)                //找到帶環鏈表的環入口點
{
    List_node *intersect = NULL;
    if(! has_circle(list, &intersect)){
        return NULL;
    }

    //轉化爲求兩個相交鏈表的第一個結點的問題
    List_node *list1_head = list->head;
    List_node *list2_head = intersect->next;

    //求得二個鏈表的長度
    List_node *p = list1_head;
    List_node *q = list2_head;

    int list1_len = 0;
    int list2_len = 0;
    int distance  = 0;

    while(p != intersect){
        list1_len++;
        p = p->next;
    }

    while(q != intersect){
        list2_len++;
        q = q->next;
    }

    p = list1_head;
    q = list2_head;

    //移動較長的鏈表 移動距離爲兩個長度的差
    if(list1_len > list2_len){
        distance = list1_len - list2_len;
        while(distance--){
            p = p->next;
        }
    }else{
        distance = list2_len - list1_len;
        while(distance--){
            q = q->next;
        }
    }

    while(p != q){
        p = p->next;
        q = q->next;
    }

    return q;
}

/////////////////////////////// 測試 //////////////////////////////////////

int main(int argc, char **argv)
{
    List* list = init_list();   //initialize
    List* list1 = init_list();
    List* tmp = NULL;
    int i = 0;
    for (i = 0; i < 10; ++i){
        push_back(list, rand() % 200);
        push_back(list1, rand() % 233);
    }
    printf("list:\n");
    sort_list_ascend(list);
    show_list(list);
    printf("list1:\n");
    sort_list_ascend(list1);
    show_list(list1);


    printf("\nmerge_result:\n");
    List* result = merge_two_lists(list, list1);
    show_list(result);

    List_node *p = find_revise_node(list, 1);
    printf("\nrevise_1_p:%d\n", p->data);

    List_node *mid = find_mid_node(list);
    printf("mid:%d\n", mid->data);

    reverse_list(list1);
    printf("reve:\n");
    show_list(list1);

    tmp = list_dump(list1);
    printf("copy:\n");
    show_list(tmp);
    printf("reve_show:\n");
    reverse_show_list(tmp);

    destory_list(&tmp);
    destory_list(&list);
    destory_list(&list1);
    destory_list(&result);
    return 0;
}
#endif

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章