1. 程式人生 > >C 資料結構中單鏈表基本操作

C 資料結構中單鏈表基本操作

C中的typedef

C中的typedef關鍵字作用是為一種資料型別定義一個新名字,這樣做的目的有兩個,一是給變數定義一個易記且意義明確的新名字,如:

typedef unsigned char BYTE;

把unsigned char型別自命名為BYTE。
另一個目的是簡化一些比較複雜的型別宣告,比如struct結構型別:

     typedef struct student  
    {  
        int age;  
        int class;  
    }stu;  
    stu stu_1; // 這樣就比原來的方式少寫了一個struct,比較省事,尤其在大量使用的時候
    struct student stu_1; //以上等價於這種定義,C中規定宣告struct物件時需要加struct關鍵字  

 

使用typedef定義結構體指標


如下定義:

typedef struct TreeNode {
    int Element;
    struct TreeNode* LeftChild;
    struct TreeNode* RightChild;
} Node,*PtrToTreeNode;

等價於:

給結構體 TreeNode 起一個別名為 Node;

給結構體指標 TreeNode* 起一個別名為 PtrToTreeNode; 即PtrToTreeNode實際上是一個指標


單鏈表基本操作

連結串列是一種線性儲存資料的結構(線性結構是一種資料的邏輯結構,其他還有樹結構、圖結構和集合結構)。連結串列的儲存內容在邏輯上連續,但物理上不一定連續。單向連結串列的組成包括:

  • 表頭(head):只有指標域,沒有資料域;
  • 結點(node):資料域+指標域;
  • 表尾:只有資料域,沒有指標域(指標為NULL);

單鏈表結點(node)的定義:

struct node{
    int num;
    struct node* Pnext;
}


C語言中連結串列的實現主要依靠結構體和指標。

實現單鏈表的 建立、列印、計算長度、刪除指定結點、頭尾插入、連結串列遞增排序、逆序、清空連結串列等操作:

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

//定義單鏈表結點結構
typedef struct Node{
    int data;
    struct Node* next;
}node;

//建立帶表頭單向連結串列,表尾插入
node* createList(const int length){
    node *head,*helper;
    helper = head = (node *)malloc(sizeof(node));
    for(int i=0;i<length;i++){
        helper = helper->next = (node *)malloc(sizeof(node));
        helper->data = i;
    }    
    helper->next = NULL;
    return head;
}

//列印連結串列
void printList(const node* list1){
    const node* p=NULL;
    p = list1->next;   //有表頭連結串列指向表頭後的結點     
    while(p){
        printf("%d\n",p->data);
        p = p->next;
    }
}

// 求連結串列長度
int length_list(const node* list1){
    int n=0;
    if(list1->next==NULL){
        return n;
    }
    while(list1->next!=NULL){
        n+=1;
        list1=list1->next;
    }
    return n;
}

//刪除資料域值為key的結點
node* delete_key(node* list1, int key){
    if(list1->next==NULL){
        return list1;   //如果為空直接返回
    }
    node* p, *del;
    for(p=list1;p->next!=NULL&&p->next->data!=key;p=p->next);
    if(p->next==NULL){
        return list1;  //如果到最後一個結點還沒有匹配到key,返回list1
    }
    del = p->next;
    p->next=p->next->next;
    free(del);
    del = NULL;
    return list1;
}

//在頭結點或尾結點插入資料key
node* insert_list(node* list1, int key, int head_or_end){
    node* insert_key = (node*)malloc(sizeof(node));
    insert_key->data = key;   
    if(head_or_end){
        insert_key->next = list1->next;
        list1->next = insert_key;
        return list1;        
    }
    else{
        node* p = list1;
        for(p = list1; p->next!=NULL;p=p->next);
        p->next = insert_key;
        insert_key->next = NULL;
        return list1;        
    }    
}

//單鏈表排序(表頭到表尾增大)
node* sort_list(node* list1){
    int length = length_list(list1);
    if(length==0){  //長度為0表示空連結串列,返回
        return list1;
    }   
    for(int i=1;i<length;i++){
        node* p = list1->next;       
        for(int j=0;j<length-i;j++){
            if(p->data>p->next->data){
                p->data+=p->next->data;
                p->next->data = p->data - p->next->data;
                p->data = p->data - p->next->data;
            }
            p=p->next;            
        }               
    }
    return list1;
}

//單鏈表逆序
node* reverse_list(node* list1){
    if(list1==NULL||list1->next==NULL){
        return list1;
    }
    node *p1, *p2, *p3;
    node *head = (node*)malloc(sizeof(node));
    p1 = list1;
    p2 = p1->next;
    while(p2!=NULL){
        p3 = p2->next;
        p2->next = p1;
        p1 = p2;
        p2 = p3;
    }
    list1->next->next=NULL;  
    head->next = p1;
    list1 = head;
    return list1;
}

//清空單鏈表
void delete_all(node* list1){
    node* p1=NULL,*p2 = NULL;
    p1 = list1->next;    
    while(p1->next!=NULL){
        p2 = p1->next;
        free(p1);
        p1 = p2;
    }
    free(p2);   
    list1->next=NULL;        
}

void main()
{
    node* List1 =createList(5);  //建立連結串列
    printList(List1);   //列印連結串列   
    printf("%d\n",length_list(List1));  //連結串列長度
    List1 = delete_key(List1,3);  //刪除連結串列結點
    List1 = insert_list(List1,66,1);  //頭結點插入資料
    List1 = insert_list(List1,77,0);  //尾結點插入資料
    List1 = sort_list(List1);    //連結串列遞增排序
    printList(List1);
    List1 = reverse_list(List1);  //連結串列逆序
    printList(List1);          
    delete_all(List1);  //清空銷燬連結串列
    printf("%d\n",length_list(List1));
    return;
}

補充兩個操作: 頭插法和查詢中間結點

// 表頭插入
node* create_list_headIN(const int length){
    node* head = (node*)malloc(sizeof(node));
    node* p;    
    for(int i=0;i<length;i++){
        p = (node*)malloc(sizeof(node));
        p->data = i;         
        p->next = head->next;
        head->next = p;            
    }
    head ;
    return head;
}

//查詢連結串列中間結點
node* middle_node(node* list1){
    node *p1,*p2;
    p1 = p2 = list1;
    while(p2 && p2->next){
        p1 = p1->next;
        p2 = p2->next->next;
    }
    printf("\n%d\n",p1->data);
    return p1;
}