數據結構-編程實現一個單鏈表的建立


1:結構體

    結構體是一種自定義數據類型。聲明結構體時使用的關鍵字是struct,定義一種結構體的一般形式為:

struct 結構體名

{

    成員列表;

}

    結構體類型與基本類型一樣,都是從C語言中繼承下來的,但是C++結構體與C語言結構體是有區別的,C語言中沒有繼承、成員函數等概念,所以C語言中的結構體成員只能包含C語言中的數據類型,不能包含成員函數;但是C++語言卻不是。

    C++中的結構體的使用方法和類的使用方法幾乎一樣,它包含this指針,可以繼承也可以被繼承;創建、銷毀和復制時均調用相應的構造、析構和復制構造函數;它包含虛表,可以被抽象化...但有兩點不同,其一,結構體的默認訪問權限為public,而類中則是private;其二,結構體無法使用類模板。

2:數據類型別名——typedef

    使用C++的typedef關鍵字可以將一個數據類型的名稱賦予別名,也可以將已經存在的別名賦予您的名字,例如:

typedef flag int;

 

    這樣,程序中的flag就可以作為int的數據類型來使用,例如:

flag a;

    a實質上是int類型的數據,此時int類型的別名就是flag。

    在聲明類或者結構體時使用typedef關鍵字,例如:

typedef class asdfgh

{

    成員列表;

}myClass,ClassA;

    這樣就可以使聲明的類擁有myClass和ClassA兩個別名。

    typedef的主要用途有如下兩個:

(1)定義很復雜的基本類型名稱,如函數指針int(*)(int i)。

typedef pFun int(*)(int i);

(2)使用其他人開發的類型時,使類名符合自己的代碼習慣(規范)。

    tpedef關鍵字具有作用域。范圍是別名聲明所在的區域(包含名稱空間)。

2:malloc函數

    malloc函數是一種分配長度為num_bytes字節的內存塊的函數,可以向系統申請分配指定size個字節的內存空間。malloc的全稱是memory allocation,中文叫動態內存分配,當無法知道內存具體位置的時候,想要綁定真正的內存空間,就需要用到動態的分配內存。

    返回類型是 void* 類型。void* 表示未確定類型的指針。C,C++規定,void* 類型可以通過類型轉換強制轉換為任何其它類型的指針。

(1)原型:

extern void *malloc(unsigned int num_bytes);

(2)頭文件:

#include <stdlib.h>
或者
#include <malloc.h>
(3)函數聲明:
void *malloc(size_t size);
    備注:void* 表示未確定類型的指針,void *可以指向任何類型的數據,更明確的說是指申請內存空間時還不知道用戶是用這段空間來存儲什么類型的數據(比如是char還是int或者其他數據類型)。
(4)返回:
    如果分配成功則返回指向被分配內存的指針(此存儲區中的初始值不確定),否則返回空指針NULL。當內存不再使用時,應使用free()函數將內存塊釋放。函數返回的指針一定要適當對齊,使其可以用於任何數據對象。
(5)說明:
    關於該函數的原型,在以前malloc返回的是char型指針,新的ANSIC標准規定,該函數返回為void型指針,因此必要時要進行類型轉換。
(6)與new的不同
    從本質上來說,malloc(Linux上具體實現可以參考man malloc,glibc通過brk()&mmap()實現)是libc里面實現的一個函數,如果在source code中沒有直接或者間接include過stdlib.h,那么gcc就會報出error:‘malloc’ was not declared in this scope。如果生成了目標文件(假定動態鏈接malloc),如果運行平台上沒有libc(Linux平台,手動指定LD_LIBRARY_PATH到一個空目錄即可),或者libc中沒有malloc函數,那么會在運行時(Run-time)出錯。new則不然,是c++的關鍵字,它本身不是函數。new不依賴於頭文件,c++編譯器就可以把new編譯成目標代碼(g++4.6.3會向目標中插入_Znwm這個函數,另外,編譯器還會根據參數的類型,插入相應的構造函數)。
    在使用上,malloc 和 new 至少有兩個不同: new 返回指定類型的指針,並且可以自動計算所需要大小。比如:
int *p;
p = new int;
//返回類型為int *類型(整數型指針),分配大小為sizeof(int);

int *parr;
parr = new int[100];
//返回類型為int *類型(整數型指針),分配大小為sizeof(int) * 100;

    而 malloc 則必須要由我們計算字節數,並且在返回后強行轉換為實際類型的指針。

int *p;
p = (int*)malloc(sizeof(int) * 128);
//分配128個(可根據實際需要替換該數值)整型存儲單元,
//並將這128個連續的整型存儲單元的首地址存儲到指針變量p中
double *pd = (double*)malloc(sizeof(double) * 12);
//分配12個double型存儲單元,
//並將首地址存儲到指針變量pd中
    第一、malloc 函數返回的是 void * 類型。
    對於C++,如果你寫成:p = malloc (sizeof(int)); 則程序無法通過編譯,報錯:“不能將 void* 賦值給 int * 類型變量”。所以必須通過 (int *) 來將強制轉換。而對於C,沒有這個要求,但為了使C程序更方便的移植到C++中來,建議養成強制轉換的習慣。
    第二、函數的實參為 sizeof(int) ,用於指明一個整型數據需要的大小。
    在規范的程序中我們有必要按照這樣的格式去使用malloc及free:
type *p;
if(NULL == (p = (type*)malloc(sizeof(type))))
/*請使用if來判斷,這是有必要的*/
{
    perror("error...");
    exit(1);
}
.../*其它代碼*/
free(p);
p = NULL;/*請加上這句*/
    malloc 也可以達到 new [] 的效果,申請出一段連續的內存,方法無非是指定你所需要內存大小。比如想分配100個int類型的空間:
int *p = (int*)malloc(sizeof(int) * 100);
//分配可以放得下100個整數的內存空間。
    另外有一點不能直接看出的區別是,malloc 只管分配內存,並不能對所得的內存進行初始化,所以得到的一片新內存中,其值將是隨機的。
除了分配及最后釋放的方法不一樣以外,通過malloc或new得到指針,在其它操作上保持一致。
(7)工作機制
    malloc函數的實質體現在,它有一個將可用的內存塊連接為一個長長的列表的所謂空閑鏈表。調用malloc函數時,它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然后,將該內存塊一分為二(一塊的大小與用戶請求的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(如果有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閑鏈上。到最后,空閑鏈會被切成很多的小內存片段,如果這時用戶申請一個大的內存片段,那么空閑鏈上可能沒有可以滿足用戶要求的片段了。於是,malloc函數請求延時,並開始在空閑鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空閑塊合並成較大的內存塊。如果無法獲得符合要求的內存塊,malloc函數會返回NULL指針,因此在調用malloc動態申請內存塊時,一定要進行返回值的判斷。
 3:編程實現一個單鏈表的建立,代碼如下:
// ConsoleApplication15.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"
#include <malloc.h>

typedef struct node//定義鏈表結構體
{
    int data;//節點內容
    node *next;//指向結構體的指針,下一個節點
}node;

node *create()//創建單鏈表
{
    int i = 0;//鏈表中數據的個數
    node *head, *p, *q;//這些的本質是節點的地址
    int x = 0;
    head = NULL;
    q = NULL;//初始化q,q代表末節點
    p = NULL;
    while (1)
    {
        printf("please input the data:");
        scanf_s("%d", &x);
        if (x == 0)
            break;//data為0時創建結束
        p = (node *)malloc(sizeof(node));//用於每次輸入鏈表的數據
        p->data = x;
        if (++i == 1)//鏈表頭的指針指向下一個節點
        {
            head = p;
            q = p;
        }
        else
        {
            q->next = p;//連接到鏈表尾端
            q = p;
        }
        q->next = NULL;/*尾結點的后繼指針為NULL(空)*/
    }
    return head;
}

int length(node *head)
{
    int len = 0;
    node *p;
    p = head->next;
    while (p != NULL)
    {
        len++;
        p = p->next;
    }
    return len;
}

void print(node *head)
{
    node *p;
    p = head;
    while (p)/*直到結點q為NULL結束循環*/
    {
        printf("%d ", p->data);/*輸出結點中的值*/
        p = p->next;/*指向下一個結點*/
    }
}

int main()
{
    node *head = create();//創建單鏈表
    printf("Length:%d\n", length(head));
    print(head);
    return 0;
}
View Code
運行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM