數據結構之鏈表C語言實現以及使用場景分析

牢騷:本篇博客兩個星期前已經存爲草稿,鑑於發生一些糟糕的事情,今天才基本完成。本人6月份應屆畢業生一枚,畢業後當天來到帝都,以後也很是順利,面試了倆家公司都成功了。一家作C++方面電商ERP,一家作wifi模塊,以爲第二家公司小,薪資低,可是以爲好玩就去了。同時,在學校也喝了很多雞湯,以爲公司小怎麼了。然而去了不到20天,公司被深圳一家公司收購了,公司動員我去深圳,我尼瑪我纔來20多天啊,有木有?並且感受公司作這麼大的決定都是隨時拍板的嗎?node

本來覺得一個公司的生命力強到能夠忽略的機率,然而當本身真實的遇到這一切,才知道這個社會有多殘忍,公司的生存可能比一個員工的生存更要困難。linux

接下來就是找工做了,跑呀,找呀。。。。。。。。           一路被忽略,一路被放鴿子,一路被無視。。。。。。。   內心五味雜陳。。。。。。。。。程序員

so,可能我仍是太菜了,這種玩計算機的心態,也許會被生活玩,惟有認真拼命的學習也許可以拯救個人頹勢。面試

感謝seven,嚴厲也好,鼓勵也好,短短的一個月,您教會了我許多,感謝您的知遇之恩!願大家去深圳一切順利!待倔強的我在北京玩上一陣!算法

————————————————————————————————————————————————————————————————————————————————數組

鏈表是數據結構中比較基礎也是比較重要的類型之一,那麼有了數組,爲何咱們還須要鏈表呢!或者說設計鏈表這種數據結構的初衷在哪裏?服務器

這是由於,在咱們使用數組的時候,須要預先設定目標羣體的個數,也即數組容量的大小,然而實時狀況下咱們目標的個數咱們是不肯定的,所以咱們老是要把數組的容量設置的很大,這樣以來就浪費了不少的空間。另外,數組在進行插入操做和刪除操做的時候,在插入或者刪除制定元素以後,咱們每每須要進行循環移位,這增長了咱們的線性開銷。數據結構

正是因爲以上的兩種主要緣由,鏈表被設計出來用於通常表的操做。爲了不上面描述數組的兩種弊端,咱們但願鏈表有一下的特色less

1 能夠靈活的擴展本身的長度。函數

2 存儲地址不連續,刪除或者插入操做的時候不須要循環移位。

要實現以上兩個特色,咱們需既要保證每一個節點的獨立性,又要保存相鄰兩個節點的聯繫。

爲此,鏈表通常被設計爲下面的形式。

Node--->Node---->Node

鏈表是由一個一個的節點組成的,能夠方便和自由的插入未知個Node,前一個節點中用指針保存着下一個節點的位置,這樣以來便順利的完成了咱們對鏈表的兩點指望,可是惟一的缺點是增長了額外的空間消耗。

————————————————————————————————————————————————————————————————————————————

鏈表的定義:

鏈表的定義通常使用結構體,在看《數據結構與算法分析》這本書的時候發現,書中頻繁的使用typedef的關鍵字,結果然的很棒不只保持的代碼的整潔程度,也讓咱們在下面的編碼過程當中少見了不少煩人的指針(固然指針仍是一直存在的)。因此這裏也借用了書中的定義方法。

struct Node;
typedef struct Node* PtrNode;
typedef PtrNode Position;
typedef PtrNode List;
struct Node{
        int Value;
        PtrNode Next;
};

下面接着書寫一個創建鏈表的函數,輸入每一個節點的值,直到這個值是-1的時候函數結束。

在這個裏面,我之前一直搞不明白爲何須要定義三個Node *,如今終於瞭解了,最終仍是複習了指針的內容明白的,這裏說一下指針實現鏈表對指針的操做很頻繁,須要比較紮實的掌握了指針以後,在來看鏈表會輕鬆不少。在下面的一段程序裏,我分別定義了head/p/tmp這三個指向節點結構體的指針,head的主要做用就像一個傳銷頭目,他會主動聯繫上一個下線p,而後他就什麼也不幹了,p接着去發展一個又一個的下線tmp,結果一串以head爲首的鏈表就出來了。

起先,我總以爲有了head,爲何還要p,這是由於若是直接使用head去指向下一個節點,head的位置也是不斷在移動的,即它永遠處於鏈表的尾端,這樣當咱們返回鏈表的時候,實際上是空值。因此,咱們須要p這個中轉環節。(其實,這種作法在指針中很是廣泛,大部分有返回指針類型的函數中,都會首先定義一個指針變量來保存函數的傳入的參數,而不是對參數直接進行操做)。

 

/*
        函數功能:建立一個鏈表
        函數描述:每次輸入一個新的整數,即把新增長一個節點存放該整數,
        當輸入的整數爲-1時,函數結束。
*/
List create()
{
        int n=0;
        Position p,head,tmp;
        head=NULL;
        tmp=malloc(sizeof(struct Node));
        if(tmp==NULL)
        {
                printf("tmp malloc failed!\n");
                return NULL;
        }
else
        {
                p=tmp;
                printf("please input the first node's message!\n");
                scanf("%d",&(tmp->Value));
        }
        while(tmp->Value!=-1)
        {
                n+=1;
                if(n==1)
                {
                        head=p;
                        tmp->Next=NULL;
                }
                else
                {
                        p->Next=tmp;
                }
                p=tmp;
                tmp=malloc(sizeof(struct Node));
                printf("please input the %d node!\n",n+1);
                scanf("%d",&(tmp->Value));
        }
        p->Next=NULL;
        free(tmp);  //free函數free掉的只是申請的空間,可是指針仍是依然存在的。
        tmp=NULL;
        return head;

}

接下來,在寫一個刪除鏈表節點的函數,輸入一個整數而後遍歷鏈表節點,當鏈表節點的值與該整數相等的時候,即把該節點刪除。

在完成這個函數首先必定要把這個過程思考清楚,不能否認我以前是一個上來就敲代碼的人,看了《劍指offer》感受這種習慣是程序員的大忌,甚至還想寫一篇博客,名字都想好了《程序員的自我修養之思考在前,代碼在後》。其實想一想也是,咱們寫程序的目的是爲了解決問題,而不是爲了簡單的寫程序,純粹的讓程序跑起來大概只會在上學那會存在吧!真實的程序開發中須要考慮幾乎全部 能想到的實際問題,因此不管程序再下,一要學會先思考清楚,再下筆寫程序。

關於這個函數,咱們要想到的是:

1 若是鏈表爲空,咱們該怎麼作,固然是直接返回。

2 若是要刪除的元素爲頭節點該怎麼辦?

3 若是要刪除的元素爲尾節點該怎麼辦?

當注意到以上三個部分,咱們的程序就可能避免掉了輸入鏈表爲空,程序直接崩潰的現象,也能夠避免刪除元素值爲頭節點時刪不掉的尷尬。咱們的程序就有了必定的魯棒性。

下面着重考慮鏈表的刪除的實現:

list:      Node_a->Node_b->Node_c->Node_d;

               list        tmp         p

 

   ------->              tmp->Next=p->Next;

 

 

list:       Node_a->Node_b----------->Node_d

                                      free(p)

假設咱們要刪除的節點爲上圖的Node_c;假設咱們可以找到Node_c的前一個位置tmp和被刪除節點位置p的話;這個時候咱們只須要執行tmp->Next=p->Next便可。

只要完成上面的分析以及考慮到各類狀況,咱們完成下面的代碼就水到渠成了。

/*
函數功能:刪除鏈表中指定值的節點(若是存在多個,只刪除第一個)
本例中輸入一個整數,刪除鏈表節點值爲這個整數的節點。
*/
List DeleteNode(List list)
{
        Position p,tmp;
        int value;
        if(list==NULL)
        {
                printf("The list is null,function return!\n");
                return NULL;
        }
        else
        {
                printf("please input the delete Node's value:\n");
                scanf("%d",&value);
        }
        p=list;
       if(p->Value==value)
        {
                list=p->Next;
                free(p);
                p=NULL;
                return list;
        }
        while(p!=NULL&&p->Value!=value)
        {
                tmp=p;
                p=p->Next;
        }
        if(p->Value==value)
        {
                if(p->Next!=NULL){
                        tmp->Next=p->Next;
                }
                else
                {
                        tmp->Next=NULL;
                }
                free(p);
                p=NULL;
        }
        return list;

}
        

 關於鏈表的使用場景分析:

鏈表在程序開發中用到的頻率仍是很是高的,因此在高級語言中每每會對鏈表進行一些實現,好比STL中list以及Java中也有相似的東西。在目前的服務器端開發,主要運用鏈表來接收一些從數據中取出來的數據進行處理。

即便你不知道鏈表的底層實現,仍然能夠成功的運用STL裏面的現成的東西。可是做爲一個學習者,我以爲會使用和從底層掌握仍然是兩個不一樣的概念,linux之父說:「talk is less,show you code」。

如下的程序,用鏈表模擬了一個電話通信錄的功能,包括添加聯繫人,查找聯繫人,以及刪除聯繫人。

PS:關於魯棒性,程序中最大的危險是使用了gets這個函數,目前先保留使用gets,等待找到工做以後在作進一步的程序完善。

 

/**************************************************************************
Programe: 
    This is a phone list write by list
    The programe is just prictise for list
Author: heat nan
Mail:964465194@qq.com
Data:2015/07/27
**************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 25
#define M 15
struct node;
typedef struct node* p_node;
typedef p_node List;
typedef p_node Position;
typedef struct node** PList;
struct node{
    char name[N];
    char number[M];
    Position next;
};
int JudgeNameExist(List list,char* name);
void AddPerson(PList list);
void PrintList(List list);
List FindPerson(List list);
List FindPersonByName(List list,char* name);
int AddPersonByName(PList list,List node);
int DeletePersonByName(PList list,char* name);
void DeletePerson(PList list);
int main()
{
    List list=NULL;
    Position p;
    char cmd[100];
        while(1)
    {
        printf("                    MAIN                 \n");
        printf("       ******* 1 add a person        *******\n");
        printf("       ******* 2 show the phone list *******\n");
        printf("       ******* 3 find  from phone list *******\n");
        printf("       ******* 4 delete from phone list *******\n\n\n");
        printf("Please input the cmd number:\n");
        gets(cmd);
        switch(cmd[0])
        {
            case '1':
                AddPerson(&list);
                break;
            case '2':
                PrintList(list);
                break;
            case '3':
                FindPerson(list);
                break;
            case '4':
                DeletePerson(&list);
                break;
            default:    
                printf("wrong cmd!\n");
                break;
            
        }
        
    }
    return 0;
}
/*
    Function:判斷要添加的聯繫人名稱是否已經存在於電話簿中.
    Input:   List 電話列表,name 要添加的聯繫人的姓名.
    Return:  已經存在返回1,不存在返回0.
*/
int JudgeNameExist(List list,char* name)
{
    if(FindPersonByName(list,name)!=NULL)
        return 1;
    else
        return 0;
}
/*
    Function:根據輸入的姓名查找聯繫人的信息節點
    Input:   要輸入的電話列表list,姓名name
    Return:  返回查找到的節點
*/
List FindPersonByName(List list,char* name)
{
    while(list!=NULL)
    {
        if(strcmp(list->name,name)==0)
            break;
        list=list->next;
    }
    return list;
}
/*
    Function:根據姓名添加新的聯繫人到聯繫人列表
    Input:   指向聯繫人列表地址的指針, 新用戶節點
    Return:  添加成功返回1,添加失敗返回0
*/
int AddPersonByName(PList list,List node)
{
    if(node==NULL)
    {
        printf("the node is NULL!\n");
        return 0;
    }
    if(*list==NULL)
    {
        *list=node;
        return 1;    
    }
    List pHead=*list;
    while(pHead->next!=NULL)
        pHead=pHead->next;
    pHead->next=node;
    return 1;
}
void AddPerson(PList list)
{
    Position tmp;
    Position p_head;
    tmp=(struct node*)malloc(sizeof(struct node));
    char name[N];
    char number[M];
    if(tmp==NULL)
    {    
        printf("malloc the tmp node failed in function add person!\n");
    }
    else
    {
        
        printf("please input the name:\n");
        gets(name);
        printf("please input the number:\n");
        gets(number);
        strcpy(tmp->name,name);
        strcpy(tmp->number,number);
        tmp->next=NULL;        
    }
    if(JudgeNameExist(*list,name)==1)
    {
        free(tmp);
        printf("the name have already exist!\n");
        return;
    }
    AddPersonByName(list,tmp);
}
/*
    Function: 打印聯繫人列表
    Input:   聯繫人列表
    
*/
void PrintList(List list)
{
    Position show;
    show=list;
    if(show==NULL)
    {
        return ;
    }
    printf("Now,we print the phone list:\n");
    while(show!=NULL)
    {
        printf("Name:%s  Number:%s\n",show->name,show->number);
        show=show->next;
    }

}
List FindPerson(List list)
{
    char name[N];
    Position pHead=list;
    printf("please input the name you will find:\n");
    gets(name);
        Position node=FindPersonByName(list,name);

    if(node!=NULL)
    printf("find success! name-> %s number-> %s\n",node->name,node->number);
    else
    printf("find failed!\n");
    return node;
}
/*
    Function:根據姓名刪除聯繫人
    Input:  指向聯繫人地址的指針,聯繫人姓名
    Output: 刪除成功返回1,失敗返回0
*/
int DeletePersonByName(PList list,char* name)
{
    if(*list==NULL||name==NULL)
        return 0;
    List pHead=*list;
    if(strcmp(pHead->name,name)==0)
    {
        *list=pHead->next;
        free(pHead);
        pHead->next==NULL;
        return 0;
    }
    List tmp=pHead->next;
    while(tmp!=NULL)
    {
        if(strcmp(tmp->name,name)==0)
        {
            pHead->next=tmp->next;
            free(tmp);
            tmp->next=NULL;
            return 1;
        }
        pHead=tmp;
        tmp=tmp->next;
    }
return 0;
    
}
void DeletePerson(PList list)
{
    List pHead=*list;
    if(pHead==NULL)
    {
        printf("there is no person you can delet\n");
        return ;
    }
    char name[N];
    printf("please input the name:\n");
    gets(name);
    DeletePersonByName(list,name);
}
相關文章
相關標籤/搜索