1. 程式人生 > >單鏈表(包含反轉、導出、循環鏈表思路)

單鏈表(包含反轉、導出、循環鏈表思路)

鏈表 循環鏈表 鏈表反轉 單鏈表 數據結構

生活永遠是自己的,美哉美哉。實習告一段落,大學也算徹底結束,就像毛不易唱的二零三,給我想要的自由。
最近學習匯編及數據結構(C語言),鏈表也總算告一段落,本篇是單鏈表的學習代碼筆記,本來也想想每一步都做圖,分享知識,讓更多的朋友去學習,但是本人局限於能力,圖片無法表達自己想要的描述,所以幹脆不做圖了。
隨後日子會有雙鏈表的操作,後面仍然會分享棧、隊列的自學筆記,也可能寫匯編8086的心得,希望大家一起共勉。
代碼可能有些繁瑣(很多地方都可以優化),只是新手 給 新手的一些參考
技術分享圖片
反轉鏈表用的叠代思路參考(引用):https://blog.csdn.net/blioo/article/details/62050967
作者:blioo
本人感覺引用文章思路非常好,適合初學者,推薦給大家,下面貼自己的學習心得:

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

typedef struct Node
{
    int data;
    struct Node *next;
}Node,*PNode;

PNode ControlLinkList(PNode PHead, int len);                         //控制函數
PNode CreateLinkList(void);                                                  //構造鏈表
int TraverseLinkList(PNode PHead);                                      //遍歷鏈表,返回鏈表長度len
void GetInfo(PNode PNew, int i);                                              //用戶信息輸入,當輸入代碼量大的時候封裝起來
void InsertLinkList(PNode PHead, int pos, int data, int len);       //插入某節點
void FindLinkList(PNode PHead, int pos);                                    //尋找某節點
void DeleteLinkList(PNode PHead, int pos);                             //刪除某節點
void ModifyLinkList(PNode PHead, int pos, int data);                //修改某數據
void ExportLinkList(PNode PHead);                                             //導出鏈表(或導出某節點之前、之後的數據稍加修改即可)
PNode ReverseLinkList(PNode PHead);                                    //逆轉鏈表
void ReleaseLinkList(PNode PHead);                                         //釋放鏈表

int main(void)
{
    PNode PHead = CreateLinkList();
    int len = TraverseLinkList(PHead);
    ControlLinkList(PHead,len);
    return 0;
}

PNode ControlLinkList(PNode PHead, int len)
{
    int pos;
    int data = 0;
    printf("請輸入插入的節點pos:\n");
    scanf("%d",&pos);
    printf("請輸入插入的數據data:\n");
    scanf("%d",&data);
    InsertLinkList(PHead, pos, data, len);
    TraverseLinkList(PHead);
    printf("請輸入查詢的節點: ");
    scanf("%d",&pos);
    FindLinkList(PHead, pos);
    printf("請輸入刪除的節點: ");
    scanf("%d",&pos);
    DeleteLinkList(PHead, pos);
    TraverseLinkList(PHead);
    printf("請輸入修改的節點: ");
    scanf("%d",&pos);
    printf("請輸入修改的數據: ");
    scanf("%d",&data);
    ModifyLinkList(PHead, pos, data);
    TraverseLinkList(PHead);
    ReverseLinkList(PHead);
    TraverseLinkList(PHead);
    ReleaseLinkList(PHead);
    return PHead;
}

void GetInfo(PNode PNew, int i)
{
    printf("請輸入 No.%d Data = ",i+1);
    scanf("%d",&PNew->data);
}

PNode CreateLinkList(void)
{
    int i;
    int len = 0;
    PNode PHead = (PNode)malloc(sizeof(Node));
    PNode PTail = PHead;
    if( NULL == PHead )
    {
        printf("內存分配失敗\n");
        exit(EXIT_FAILURE);
    }

    PTail->next = NULL;
    printf("請輸入節點個數: ");
    scanf("%d",&len);

    for( i = 0; i < len; i++ )
    {
        PNode PNew = (PNode)malloc(sizeof(Node));
        if( NULL == PNew )
        {
            printf("內存分配失敗\n");
            exit(EXIT_FAILURE);
        }
        GetInfo(PNew, i);
        PTail->next = PNew;
        PNew->next = NULL;
        PTail = PNew;
    }
    printf("共%d個鏈表創建成功\n",i+1);
    return PHead;
}

int TraverseLinkList(PNode PHead)
{
    int len = 0;
    PNode p = PHead->next;
    while( NULL != p)
    {
        len++;
        printf("No.%d Data = %d\n",len,p->data);
        p = p->next;
    }
    printf("遍歷完成\n");
    return len;
}

void InsertLinkList(PNode PHead, int pos, int data, int len)            
{
    int i = 0;
    PNode p = PHead->next;
    if( NULL != p )
    {
        PNode PNew = (PNode)malloc(sizeof(Node));
        if( NULL == PNew )
        {
            printf("分配內存失敗");
            exit(EXIT_FAILURE);
        }
//      printf("LEN = %d\n",len);
        if( 0 != pos-1 )
        {
            int l = 1;                                        //為了彌補i從0開始
            while( l < pos-1 )                          //中間插法
            {
                l++;
                p = p->next;
            }
            PNew->data = data;
            PNew->next = p->next;
            p->next = PNew;
        }
        /*
        else if( pos > len && 0 != pos-1 )              //插入鏈表尾
        {
            while( i < len )
            {
                i++;
                p = p->next;
            }
            p->next = PNew;                                    //最後一個p節點指向NULL
            PNew->data = data;
            PNew->next = NULL;
        }
        */
        else
        {
            PHead->next = PNew;                         //插入鏈表頭
            PNew->data = data;
            PNew->next = p; 
        }
    }
    else
    {
        printf("空鏈表\n");
    }
}

void FindLinkList(PNode PHead, int pos)
{
    int i = 0;
    PNode p = PHead->next;
    if( NULL != p )
    {
        while( i < pos-1 )
        {
            i++;
            p = p->next;
        }
        printf("查找元素成功,數據如下:\n");
        printf("No.%d Data = %d\n",i+1,p->data);
    }
    else
    {
        printf("鏈表為空\n");
    }
}   

void DeleteLinkList(PNode PHead, int pos)
{
    int i = 0;
    PNode p = PHead->next;
    PNode PTemp;
    while( NULL != p && i != (pos-1) )
    {
        i++;
        p = p->next;
    }
    PTemp = p->next;
    p->next = p->next->next;
    free(PTemp);
    PTemp = NULL;
    printf("刪除節點成功\n");

}

void ModifyLinkList(PNode PHead, int pos, int data)
{
    int i = 0;
    PNode p = PHead->next;
    while( NULL != p && i != pos-1 )                               //一般用這種方式來判空與循環代碼簡潔
    {
        i++;
        p = p->next;
    }
    p->data = data;
    printf("修改數據成功:\n");
    printf("No.%d  Data = %d\n\n",i,p->data);
}

void ExportLinkList(PNode PHead)
{
    FILE *fp;
    PNode p = PHead->next;

    if( (fp = fopen("LinkList.txt","ab")) == NULL )
    {
        printf("讀取文件失敗,創建文件成功");
        exit(EXIT_FAILURE);
    }

    while( NULL != p )
    {
        fputc(p->data,fp);
        p = p->next;
    }

    printf("導出成功");
    fclose(fp);
}

PNode ReverseLinkList(PNode PHead)
{
    PNode q = NULL;                     //作為反轉節點
    PNode Ptemp = NULL;             //建立新節點指向下一個
    PNode p = PHead->next;          //指向第一個鏈表數據
    PHead->next = NULL;             //頭結點為空
    while( NULL != p )
    {
        Ptemp = p->next;                    //下一個節點
        p->next = q;                         //指向反轉節點
        q = p;                                    //q指向前一個節點p  q->next = p;
        p = Ptemp;                          //p接著去下一個節點
    }
    PHead->next = q;                    //頭結點指向翻轉後的鏈表
    printf("鏈表翻轉成功\n");     
    return PHead;
}

void ReleaseLinkList(PNode PHead)
{
    PNode p = PHead->next;
    PNode temp;
    PHead->next = NULL;
    free(PHead);
    while( NULL != p )
    {

        temp = p->next;
        free(p);
        p = temp;
    }
    free(temp);
    printf("釋放成功!\n");
}

代碼在window7 64 VC++6.0編譯通過粘貼,代碼可能縮進有些不好看。
下面說一說循環單鏈表思路,姑且以我的認識和實際的應用,就是就體現在循環的不同。
在創建單鏈表的時候,最後把PNew->next = NULL 改為 PNew->next = PHead;
這裏PHead是頭結構體指針,所以->next才是指向第一個數據。
循環單鏈表,PHead可以從鏈表任意節點開始遍歷都可以遍歷整個鏈表。
註意:循環條件不可以是while( NULL !=p ),因為循環鏈表沒有NULL值,進入死循環了就。
頭尾相連,遍歷條件應該改為 while( PHead != p ),頭不等於p不就解決了。

單鏈表(包含反轉、導出、循環鏈表思路)