Google Code Prettify

2011年1月4日 星期二

C - Linked List (鏈結串列) Part 1

作業要求:練習用結構指標做出一鏈結串列並對其做運算。

這作業我搞了整個週末才寫出個雛形,說寫了超過24小時一點也不為過。

由於第一次寫這麼大結構的程式,故程式碼有些冗長且重複使用性極低。僅供參考。




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

struct node { //宣告singly linked list結構
    int data;
    struct node *next;
};

struct nodeDLL { //宣告doubly linked list結構
    int data;
    struct nodeDLL *prev, *next;
};

struct node *first = NULL; //宣告指向首端的結構指標
struct nodeDLL *firstDLL = NULL, *tailDLL = NULL; //宣告指向首端及尾端的結構指標

void build_a_list(struct node **first, int n); //宣告singly linked list函數群
void print_list(struct node *first);
void clean_list(struct node *first);
void insert_to_list(struct node **first);
void search_list();
void delete_from_list();
void count_list();
void reverse_list();
void merge_list(int n);
void split_list();

void build_a_DLL(struct nodeDLL **firstDLL, struct nodeDLL **tailDLL, int n); //宣告doubly linked list函數群
void prePrint_DLL(struct nodeDLL *firstDLL);
void postPrint_DLL(struct nodeDLL *firstDLL);
void clean_DLL(struct nodeDLL *firstDLL);
void insert_to_DLL(struct nodeDLL **firstDLL, struct nodeDLL **tailDLL);
void search_DLL();
void delete_from_DLL();
void count_DLL();
void reverse_DLL();
void merge_DLL(int n);
void split_DLL();

int main(void)
{
    int DS, n; //DS讀入資料結構型態
    char F; //F讀入執行函數類型

    printf("Please select the data structure or exit: ");
    scanf("%d", &DS);
    srand(time(NULL));
    n = rand() % 10 + 3; //先創造一隨機長度的linked list
    if (DS == 1) {
        printf("Please enter %d numbers to create a initial list: ", n);
        build_a_list(&first, n);
        print_list(first);
    }
    else if (DS == 2) {
        printf("Please enter %d numbers to create a initial list: ", n);
        build_a_DLL(&firstDLL, &tailDLL, n);
        prePrint_DLL(firstDLL);
    }
    else
        return 0;

    while (1) {
        getchar(); //吸收多input的Enter
        printf("Please select the function: ");
        scanf("%c", &F);
        if (DS == 1) { //若選擇singly linked list則執行此選單
            switch (F) {
            case 'a':
                printf("Enter the number you want to insert: ");
                insert_to_list(&first);
                break;
            case 'b':
                delete_from_list();
                break;
            case 'c':
                search_list();
                break;
            case 'd':
                count_list();
                break;
            case 'e':
                reverse_list();
                break;
            case 'f':
                merge_list(n);
                break;
            case 'g':
                split_list();
                break;
            case 'h':
                print_list(first);
                break;
            case 'x':
                clean_list(first);
                return 0;
            }
        }
        else { //若選擇doubly linked list則執行此選單
            switch (F) {
            case 'a':
                printf("Enter the number you want to insert: ");
                insert_to_DLL(&firstDLL, &tailDLL);
                break;
            case 'b':
                delete_from_DLL();
                break;
            case 'c':
                search_DLL();
                break;
            case 'd':
                count_DLL();
                break;
            case 'e':
                reverse_DLL();
                break;
            case 'f':
                merge_DLL(n);
                break;
            case 'g':
                split_DLL();
                break;
            case 'h':
                prePrint_DLL(firstDLL);
                break;
            case 'i':
                postPrint_DLL(tailDLL);
                break;
            case 'x':
                clean_DLL(firstDLL);
                return 0;
            }
        }
    }
}

void build_a_list(struct node **first, int n) //創造一隨機長度的linked list
{
    int i;
    struct node *new_node, *prev = NULL, *cur;

    new_node = malloc(sizeof(struct node)); //創造第一個節點空間
    if (new_node == NULL) { //若創造失敗則印出錯誤
        printf("Error: malloc failed.\n");
        return;
    }
    new_node->next = *first; //first指向第一個節點
    *first = new_node;
    for (i = 0; i < n; i++) {
        cur = *first;
        scanf("%d", &new_node->data); //讀入數字到節點
        while (cur->data < new_node->data && cur->next != NULL) { //由小到大排列節點
            prev = cur;
            cur = cur->next;
        }
        if (cur->data < new_node->data && cur->next == NULL) { //若原始list內沒有節點的數字比欲插入之節點大,則節點放到尾端
            cur->next = new_node;
            new_node->next = NULL;
        }
        else if (prev == NULL) { //若首端節點數字即比欲插入節點大,則將first指向欲插入之節點,並將節點與原list連結
            if (new_node->next == NULL) //若list內無任何節點,則不需做連結
                ;
            else {
                *first = new_node;
            }
        }
        else { //若為其他狀況則將前一個節點和欲插入之節點連結,欲插入之節點和後一個節點連結
            prev->next = new_node;
            new_node->next = cur;
        }
        new_node = malloc(sizeof(struct node)); //再創一個新節點空間
        if (new_node == NULL) { //若創造失敗則印出錯誤
            printf("Error: malloc failed.\n");
            return;
        }
        if (i == n - 1) //若為最後一次跑for loop,則釋放剛創的節點空間
            free(new_node);
    }
}

void print_list(struct node *first) //印出linked list
{
    if (first == NULL) { //若無list,則印出訊息
        printf("There is no list.\n");
        return;
    }
    struct node *cur;

    for (cur = first; cur != NULL; cur = cur->next) //從第一個節點開始循序印出數字
        printf("%d ", cur->data);
    printf("\n");
}

void clean_list(struct node *first) //清除linked list
{
    struct node *prev, *cur;

    for (cur = first; cur != NULL;) {
        prev = cur;
        cur = cur->next;
        first = cur;
        free(prev);
    }
    first = NULL;
}

void insert_to_list(struct node **first) //插入一個新節點
{
    struct node *new_node, *prev = NULL, *cur;

    new_node = malloc(sizeof(struct node)); //創造新節點空間
    if (new_node == NULL) { //若創造失敗則印出訊息
        printf("Error: malloc failed.\n");
        return;
    }
    scanf("%d", &new_node->data); //讀入數字
    if (*first == NULL) { //若無list可插入新節點則印出訊息
        printf("There is no list to insert a new node.\n");
        free(new_node);
        return;
    }
    for (cur = *first; cur->data < new_node->data && cur->next != NULL;) { //確定新節點位置
        prev = cur;
        cur = cur->next;
    }
    if (prev == NULL) { //若為第一個則first指向新節點,並將新節點與原list連結
        new_node->next = *first;
        *first = new_node;
    }
    else {
        if (cur->next == NULL) { //若為最後一個則原list尾端節點與之連結
            cur->next = new_node;
            new_node->next = NULL;
        }
        else { //其他狀況則前一個和後一個與之連結
            prev->next = new_node;
            new_node->next = cur;
        }
    }
}

void delete_from_list() //從list中刪除一個節點
{
    int n;
    struct node *cur, *prev = NULL;

    if (first == NULL) { //若無list則印出訊息
        printf("Nothing to delete.\n");
        return;
    }
    printf("Enter the number you want to delete: "); //印出要求
    scanf("%d", &n); //讀入數字
    for (cur = first; cur != NULL && cur->data != n; prev = cur, cur = cur->next) //定位
        ;
    if (cur == NULL) { //若找不到欲刪除之節點則印出訊息
        printf("The number doesn't exist in the list.\n");
        return;
    }
    else if (prev == NULL) //若為首端節點則將first指向下一個節點
        first = cur->next;
    else //其他狀況則前一個與後一個連結
        prev->next = cur->next;
    free(cur); //釋放節點空間
    printf("The node has been deleted.\n"); //印出訊息
}

void search_list() //搜尋節點
{
    int n, num_node = 1;
    struct node *cur;

    cur = first;
    printf("Enter the number you want to search: "); //印出要求
    scanf("%d", &n); //讀入數字
    for (; cur != NULL; cur = cur->next, num_node++) //搜尋是否存在
        if (cur->data == n) {
            printf("The number is in no.%d list.\n", num_node); //存在則印出訊息
            return;
        }
    printf("The number doesn't exist in the list.\n"); //不存在則印出訊息
}

void count_list() //計算節點數
{
    int num_nodes = 0;
    struct node *cur;

    for (cur = first; cur != NULL; cur = cur->next) //計算節點數後印出結果
        num_nodes++;
    printf("There are %d nodes in the list.\n", num_nodes);
}

void reverse_list() //反轉list
{
    struct node *prev, *cur;

    cur = first;
    first = NULL;
    while (cur != NULL) { //反轉各節點間的連結並改變first指向
        prev = cur;
        cur = cur->next;
        prev->next = first;
        first = prev;
    }
    printf("The list has been reversed.\n"); //印出訊息
}

void merge_list(int n) //合併兩條linked list
{
    int i;
    struct node *head = NULL;

    srand(time(NULL));
    n = rand() % 10 + 1;
    printf("Please enter %d numbers for the first list: ", n); //輸入第一條list並創建
    build_a_list(&head, n);
    n = rand() % 10 + 1;
    printf("Please enter %d numbers for the second list: ", n); //輸入第二條list並插入第一條list中
    for (i = 0; i < n; i++)
        insert_to_list(&head);
    printf("The merged list:\n");
    print_list(head);
    printf("But the initial list won't change.\n"); //並不會改變最初創建的initial list
    clean_list(head);
}

void split_list() //將list分成奇數及偶數並印出
{
    struct node *cur, *even = NULL, *odd = NULL;

    for (cur = first; cur->data % 2 != 0 && cur->next != NULL; cur = cur->next) //找存偶數的第一個節點
        ;
    if (cur->data % 2 != 0 && cur->next == NULL) {
        printf("There is no even number in the list.");
        return;
    }
    else
        even = cur;
    for (cur = first; cur->data % 2 == 0 && cur->next != NULL; cur = cur->next) //找存奇數的第一個節點
        ;
    if (cur->data % 2 == 0 && cur->next == NULL) {
        printf("There is no odd number in the list.");
        return;
    }
    else
        odd = cur;
    cur = even;
    printf("The even list:\n%d ", cur->data); //依序找出存偶數的節點並印出
    while (cur->next != NULL) {
        cur = cur->next;
        while (cur->data % 2 != 0 && cur->next != NULL)
            cur = cur->next;
        if (cur->data % 2 == 0)
            printf("%d ", cur->data);
        else
            break;
    }
    printf("\n");
    cur = odd;
    printf("The odd list:\n%d ", cur->data); //依序找出存奇數的節點並印出
    while (cur->next != NULL) {
        cur = cur->next;
        while (cur->data % 2 == 0 && cur->next != NULL)
            cur = cur->next;
        if (cur->data % 2 != 0)
            printf("%d ", cur->data);
        else
            break;
    }
    printf("\n");
}

沒有留言:

張貼留言