1. 程式人生 > >2.線性表的鏈式儲存結構————單鏈表(思路分析,C語言、C++完整程式)

2.線性表的鏈式儲存結構————單鏈表(思路分析,C語言、C++完整程式)

目錄

1.單鏈表的基本概念

(1)單鏈表:當連結串列中的每個結點只含有一個指標域時,稱為單鏈表。

(2)頭指標:如上圖所示,連結串列中第一個結點的儲存位置叫做頭指標。

(3)頭結點:頭結點是放在第一個元素結點之前的結點,頭結點不是連結串列中的必須元素,其資料域一般無意義,(有些情況下會存放連結串列的長度,或用作監視哨等),本文的頭結點存放了連結串列的長度。有了頭結點後,對在第一個元素結點前插入結點和刪除第一個結點,其操作與對其它結點的操作統一了。

(4)首元結點:就是第一個元素的結點,它是頭結點後邊的第一個結點。

2.單鏈表的基本操作

(1)初始化:給連結串列新增一個頭結點。

(2)逆置連結串列:將單鏈表所有元素逆置。

(3)連結串列遍歷:打印出連結串列的長度,並按順序列印所有元素。

(4)查詢:獲取指定位置的元素。

(5)元素插入:在指定位置插入元素。

(6)元素刪除:刪除指定位置的元素。

(7)刪除連結串列:將連結串列刪除。

(8)頭插法建立連結串列:用頭插法插入一系列元素,建立連結串列。

(9)尾插法建立連結串列:用尾插法插入一系列元素,建立連結串列。

(10)快慢指標:利用快慢指標法的原理,快速查詢一個長度未知的連結串列的中間結點。

這些操作中,連結串列逆置具有一定的難度,其基本的設計思想是:將以前的舊連結串列中的每個元素從舊連結串列中刪除,並用頭插法插入新的連結串列中。

快慢指標的設計也非常巧妙,快指標運動速度是慢指標的兩倍,因此快指標指向最後一個結點的時候,慢指標剛好指向中間結點。

3.單鏈表程式設計實現----C語言

在C語言中函式和資料是分開的,每個函式都需要考慮連結串列的資料傳遞問題,這大大加大了程式設計的難度。

(1)連結串列的標頭檔案 linklist.h

#ifndef LINKLIST_H
#define LINKLIST_H

typedef int ElemType;
typedef struct Node
{
    ElemType data;
    struct Node *Next;
}Node;

typedef Node* linklist;//給節點指標取別名
typedef enum Bool
{
    FALSE,TRUE//列舉預設值從0開始,依次加1
}Bool;

Bool InitList(linklist* L);//初始化連結串列,給連結串列新增一個頭結點
Bool GetElem(linklist L, int i, ElemType* e);//獲得第i個位置的元素
Bool ListInsert(linklist* L,int i,ElemType e);//在第i個位置插入元素
Bool ListDelete(linklist* L,int i,ElemType* e);//刪除第i個元素
Bool ListDeleteAll(linklist* L);//刪除全部連結串列
void traverseList(linklist L);//遍歷連結串列
void CreateListHead(linklist* L,int n);//頭插法建立連結串列
void CreateListEnd(linklist* L,int n);//尾插法建立連結串列
void Reverse(linklist* L);//逆置連結串列
int findMiddle(linklist L, ElemType* e);//查詢中間結點,將查詢的元素值賦給e,並返回該節點是第幾個結點,如果是空表則返回0

#endif // LINKLIST_H

(2)連結串列的原始檔linklist.c

#include "linklist.h"
#include <stdio.h>

Bool GetElem(linklist L, int i, ElemType* e)
{
    linklist p=L;
    int j;
    for(j=1;j<=i;j++)
    {
        p=p->Next;
        if(p==NULL)
            return FALSE;
    }
    *e=p->data;
    return TRUE;
}

Bool ListInsert(linklist* L,int i,ElemType e)
{
    linklist p=*L,s;

    int j;
    for(j=1;j<i;j++)
    {
        p=p->Next;
        if(p==NULL)
            return FALSE;
    }
    s=(linklist)malloc(sizeof(Node));
    s->data=e;
    s->Next=p->Next;
    p->Next=s;
    (*L)->data++;
    return TRUE;
}

Bool ListDelete(linklist* L,int i,ElemType* e)
{
    linklist p=*L,q;
    int j;
    for(j=1;j<i;j++)
    {
        p=p->Next;
        if(p==NULL)
            return FALSE;
    }

    q=p->Next;
    p->Next=q->Next;
    (*L)->data--;

    *e=q->data;
    free(q);
    return TRUE;
}

Bool InitList(linklist* L)
{
    *L=(linklist)malloc(sizeof(Node));
    (*L)->data=0;
    (*L)->Next=NULL;
    return TRUE;
}

void traverseList(linklist L)
{
    linklist p=L;
    printf("連結串列總長度為:%d  \n",p->data);
    p=p->Next;
    while(p)
    {
        printf("%d  ",p->data);
        p=p->Next;
    }
    printf("\n\n");
//    printf("display ok!\n");
}

void CreateListHead(linklist* L,int n)
{
    linklist p;
    int i;

    for(i=0;i<n;i++)
    {
        p=(linklist)malloc(sizeof(Node));
        p->data=i;//rand()%100+1;
        p->Next=(*L)->Next;
        (*L)->Next=p;
        (*L)->data++;
    }
}

void CreateListEnd(linklist* L,int n)
{
    linklist p,end=*L;
    int i;

    for(i=0;i<n;i++)
    {
        p=(linklist)malloc(sizeof(Node));
        p->data=i;//rand()%100+1;
        p->Next=NULL;
        end->Next=p;
        end=p;
        (*L)->data++;
    }
}

Bool ListDeleteAll(linklist* L)
{
    linklist p=*L,q;
    while(p->Next)
    {
        q=p->Next;
        p->Next=q->Next;
        (*L)->data--;
        free(q);
    }
    free(p);
    return TRUE;
}

void Reverse(linklist* L)//翻轉連結串列
{
    linklist cur, tmp;

    //初始化新的頭結點
    cur=*L;
    cur=cur->Next;//舊連結串列的頭結點被刪除(賦給了新的頭結點)
    (*L)->Next=NULL;//注意這一句和上一句不能顛倒,不然cur無法向後移

    while (cur)
    {
        tmp=cur;
        cur=cur->Next;//順序刪舊連結串列的元素
        tmp->Next=(*L)->Next;//被刪掉的元素用頭插法插入新的頭結點
        (*L)->Next=tmp;
    }
}

int findMiddle(linklist L, ElemType* e)
{
    linklist fast,slow;
    int i;
    fast=slow=L;

    for(i=0;fast!=NULL&&fast->Next!=NULL;fast=fast->Next->Next)
    {
        slow=slow->Next;
        i++;
    }
    *e=slow->data;
    return i;
}

(3) 主程式main.c

#include <stdio.h>
#include "linklist.h"

int main()
{
    ElemType a;
    linklist list;
    int num;

    printf("           1.初始化\n");
    InitList(&list);
    traverseList(list);

    InitList(&list);
    printf("        2.尾插法新建單鏈表\n");
    CreateListEnd(&list,10);
    traverseList(list);
    ListDeleteAll(&list);

    InitList(&list);
    printf("        3.頭插法新建單鏈表\n");
    CreateListHead(&list,10);
    traverseList(list);

    printf("            4.元素插入\n");
    ListInsert(&list,5,10);
    traverseList(list);

    printf("            5.元素刪除\n");
    ListDelete(&list,5,&a);
    printf("被刪除的元素為:%d  ",a);
    traverseList(list);

    printf("            6.元素查詢\n");
    GetElem(list,3,&a);
    printf("第3個元素為:%d  \n\n\n",a);

    printf("             7.逆置連結串列\n");
    printf("原連結串列----------");
    traverseList(list);
    Reverse(&list);
    printf("逆置連結串列---------");
    traverseList(list);

    printf("\n\n             8.快慢指標查詢中間結點\n");
    printf("原連結串列\n");
    traverseList(list);
    num=findMiddle(list,&a);
    printf("中間結點為%d,這是連結串列的第%d個結點\n\n\n",a,num);

    ListDeleteAll(&list);
    return 0;
}

4.單鏈表程式設計實現----C++

(1)連結串列類的宣告 linklist.h

#ifndef LIST_H
#define LIST_H

template<typename ElemType>//typedef int ElemType;
class List
{
public:
    struct Node
    {
        ElemType data;
        struct Node *next;
    };
    List();//連結串列,可以刪除所有動態節點
    ~List();//刪除全部節點
    void traverseList();//遍歷
    bool ListInsert(int i,ElemType d);//在第i個節點位置插入元素d
    void CreateListHead(int n);//頭插法插入
    void CreateListEnd(int n);//尾插法插入
    void Reverse();//逆置單鏈表
    bool ListDelete(int i,ElemType& e);//刪除第i個元素
    bool GetElem(int i,ElemType& e);//獲取第i個節點位置的元素,並且返回給e
    int findMiddle(ElemType& e);//查詢中間結點,將查詢的元素值賦給e,並返回該節點是第幾個結點,如果是空表則返回0
private:
    Node *head;//存放頭結點
};

#endif // LIST_H

(2)連結串列類的實現linklist.cpp

#include "linklist.h"
#include<iostream>
using namespace std;

template<typename ElemType>
List<ElemType>::List()//初始化
{
    head=new Node;
    head->next=NULL;
    head->data=0;//頭指標的資料域也不要浪費:用來存放連結串列長度

}

template<typename ElemType>
List<ElemType>::~List()//刪除
{
    Node* del;
    while (head->next!=NULL)
    {
        del=head;
        head=head->next;
        delete del;
    }
    delete head;
}

template<typename ElemType>
void List<ElemType>::traverseList()//遍歷
{
    Node *ph=head;
    cout<<"連結串列總長度為:"<<head->data<<endl;
    ph=ph->next;
    for(;ph!=NULL;ph=ph->next)
        cout<<ph->data<<"  ";
    cout<<endl;
}

template<typename ElemType>
void List<ElemType>::CreateListHead(int n)//頭指標插入
//頭插法:
//head->NULL;
//head->p1->NULL;
//head->p2->p1->NULL;
{
    for(int i=0;i<n;i++)
    {
        Node* cur=new Node;
        cur->data=i;
        cur->next=head->next;
        head->next=cur;
        head->data++;
    }
}

template<typename ElemType>
bool List<ElemType>::ListInsert(int i,ElemType d)
{
    Node *p=head,*cur;

    for(int j=1;j<i;j++)
    {
        p=p->next;
        if(p==NULL)
            return false;
    }
    cur=new Node;
    cur->data=d;
    cur->next=p->next;

    p->next=cur;

    head->data++;
    return true;
}

template<typename ElemType>
void List<ElemType>::CreateListEnd(int n)//末尾插入
//尾插法:
//head->NULL;
//head->p1->NULL;
//head->p1->p2->NULL;
{
    Node* cur,*end;
    end=head;
    for(int i=0;i<n;i++)
    {
        cur=new Node;
        cur->data=i;
        cur->next=end->next;
        end->next=cur;
        end=cur;
        head->data++;
    }
}

template<typename ElemType>
bool List<ElemType>::ListDelete(int i,ElemType& e)
{
    Node *p=head,*cur;

    for(int j=1;j<i;j++)
    {
        p=p->next;
        if(p==NULL)
            return false;
    }
    cur=p->next;//待刪除節點
    e=cur->data;
    p->next=cur->next;//將待刪除節點的後一個節點賦給其前一個節點
    head->data--;
    delete cur;
    return true;
}

template<typename ElemType>
bool List<ElemType>::GetElem(int i,ElemType& e)
{
    Node* p=head;

    for(int j=0;j<i;j++)
    {
        p=p->next;
        if(p==NULL)
            return false;
    }
    e=p->data;
    return true;
}

/*
 *這個程式是原始版本的程式,這個程式的思路更加清晰,下面一個程式是改進的程式,程式碼更加簡潔。
 */
/*
void List<ElemType>::Reverse()//翻轉連結串列
{
    Node* cur=head;//頭插法
    Node* newhead,*tmp;

    //初始化新的頭結點
    newhead=head;
    cur=cur->next;//舊連結串列的頭結點被刪除(賦給了新的頭結點)
    newhead->next=NULL;//注意這一句和上一句不能顛倒,不然cur無法向後移

    while (cur)
    {
        tmp=cur;
        cur=cur->next;//順序刪舊連結串列的元素
        tmp->next=newhead->next;//被刪掉的元素用頭插法插入新的頭結點
        newhead->next=tmp;
    }
    head= newhead;//這一步是多餘的,因為新頭和舊頭都是指向同一位置,其實newhead是一個多餘變數,直接用head也是可以完成任務的。
}
*/

template<typename ElemType>
void List<ElemType>::Reverse()//翻轉連結串列
{
    Node* cur,* tmp;//頭插法

    //初始化新的頭結點
    cur=head;
    cur=cur->next;//舊連結串列的頭結點被刪除(賦給了新的頭結點)
    head->next=NULL;//注意這一句和上一句不能顛倒,不然cur無法向後移

    while (cur)
    {
        tmp=cur;
        cur=cur->next;//順序刪舊連結串列的元素
        tmp->next=head->next;//被刪掉的元素用頭插法插入新的頭結點
        head->next=tmp;
    }
}

template<typename ElemType>
int List<ElemType>::findMiddle(ElemType& e)
{
    Node *fast,*slow;
    int i;
    fast=slow=head;

    for(i=0;fast!=NULL&&fast->next!=NULL;fast=fast->next->next)
    {
        slow=slow->next;
        i++;
    }
    e=slow->data;
    return i;
}

(3)主程式main.cpp

#include <iostream>
#include"linklist.cpp"

using namespace std;

int main()
{

    List<int> list;
    bool success;
    cout<<"                  1.初始化"<<endl;
    list.traverseList();

    List<int> list1;
    list1.CreateListEnd(10);
    cout<<endl<<endl<<"         2.尾插法新建單鏈表 "<<endl;
    list1.traverseList();

    List<int> list2;
    cout<<endl<<endl<<"         3.頭插法新建單鏈表 "<<endl;
    list2.CreateListHead(10);
    list2.traverseList();

    cout<<endl<<endl<<"             4.元素插入"<<endl;
    list2.ListInsert(5,10);
    list2.traverseList();

    cout<<endl<<endl<<"             5.元素刪除"<<endl;
    int a;
    list2.ListDelete(5,a);
    cout<<"被刪除的元素為:"<<a<<"  ";
    list2.traverseList();

    cout<<endl<<endl<<"             6.元素查詢"<<endl;
    list2.traverseList();
    success=list2.GetElem(3,a);
    if(!success)
        cout<<"error"<<endl;
    else
        cout<<"被查詢的元素為:"<<a<<endl;

    cout<<endl<<endl<<"             7.逆置連結串列"<<endl;
    cout<<"原連結串列"<<endl;
    list2.traverseList();
    list2.Reverse();
    cout<<endl<<"逆置連結串列"<<endl;
    list2.traverseList();

    cout<<endl<<endl<<"             8.快慢指標查詢中間結點"<<endl;
    int num;
    cout<<"原連結串列"<<endl;
    list2.traverseList();
    num=list2.findMiddle(a);
    cout<<"中間結點為"<<a<<",這是連結串列的第"<<num<<"個結點"<<endl<<endl<<endl;
    return 0;
}

5.實驗結果

相關推薦

2.線性儲存結構————單鏈思路分析C語言C++完整程式

目錄 1.單鏈表的基本概念 (1)單鏈表:當連結串列中的每個結點只含有一個指標域時,稱為單鏈表。 (2)頭指標:如上圖所示,連結串列中第一個結點的儲存位置叫做頭指標。 (3)頭結點:頭結點是放在第一個元素結點之前的結點,頭結點不是連結串列中的必

資料結構線性儲存結構單鏈(C++)

一. 標頭檔案—linkedlist.h 1 #ifndef _LIKEDLIST_H_ 2 #define _LIKEDLIST_H_ 3 4 #include <iostream> 5 6 template <class T> 7 struc

【資料結構線性儲存結構--單鏈

1. 線性表的鏈式儲存結構 鏈式儲存:用一組任意的儲存單元儲存線性表中的資料元素。用這種方法儲存的線性表簡稱線性連結串列。 儲存連結串列中結點的一組任意的儲存單元可以是連續的,也可以是不連續的,甚至是零散分佈在記憶體中的任意位置上的。 連結串列中結點的邏輯順序和物理順序不

線性——儲存結構合併操作

     採取的結構和上一篇博文一致,均為單鏈表儲存結構。#include<iostream> #include<stdio.h> #include<stdlib.h> #define ElemType int #define Status

順序儲存結構儲存結構的比較也可以說的順序與連結串列的比較

1、鏈式儲存結構的儲存空間在邏輯上是連續的,但是在物理上是離散的;而順序儲存結構的儲存空間在邏輯上是連續的,在物理上也是連續的。 2、鏈式儲存儲存密度小,但空間利用率較高;順序儲存儲存密度大,但空間利用率較低。 3、順序結構優點是可以隨機讀取元素,缺點是插入和刪除元素要移動大量元素,

二叉樹的儲存結構及實現C語言完整程式碼+詳細註釋

鏈式儲存結構儲存二叉樹,實際上就是採用連結串列儲存二叉樹。 既然是使用連結串列,首先需要構建連結串列中節點的結構。考慮到儲存物件為二叉樹,其各個節點最多包含 3 部分,依次是:左孩子、節點資料和右孩子,因此,連結串列的每個節點都由這 3 部分組成: 圖 1 二叉連結串列結點構成 圖 1 中,Lchi

2.3 線性儲存結構(連結串列)

基本概念和特點 連結串列的定義 -線性表的鏈式儲存結構稱之為連結串列(linked list)。連結串列包括兩部分構成:資料域和指標域。資料域儲存資料元素,指標域描述資料元素的邏輯關係。 - 連結串列通常使用帶頭結點的表示。指向頭結點的指標稱之為頭指標

資料結構 筆記:線性儲存結構

鏈式儲存的定義 為了表示每個資料元素與其直接後繼元素之間的邏輯關係;資料元素出了儲存本身的資訊外,還需要儲存直接後繼的資訊。 ps:在邏輯上,元素之間是相鄰的;在實體記憶體中元素之間並無相鄰關係。 鏈式儲存邏輯結構 -基礎鏈式儲存結構的線性表中,每個節點都包含資料域和指標域 ·資

大話資料結構 —— 3.6 線性儲存結構

3.6.1 順序儲存結構不足的解決辦法 C同學:反正要在相鄰元素間留多少空間都是有可能不夠的,那不如乾脆不要考慮相鄰位置這個問題了。哪裡有空位就放在哪裡,此時指標剛好可以派上用場。 每個元素多用一個

線性儲存結構的基本操作(經編譯)

/* 連結串列銷燬的時候,是先銷燬了連結串列的頭,然後接著一個一個的把後面的結點銷燬了,這樣這個連結串列就不能再使用了。 連結串列清空的時候,是先保留了連結串列的頭,然後把頭後面的所有的結點都銷燬,最後把頭裡指向下一個的指標設為空,這樣就相當與清空了,但這個連結

線性包括順序儲存結構儲存結構

還記得資料結構這個經典的分類圖吧: 今天主要關注一下線性表。 什麼是線性表 線性表的劃分是從資料的邏輯結構上進行的。線性指的是在資料的邏輯結構上是線性的。即在資料元素的非空有限集中 (1) 存在唯一的一個被稱作“第一個”的資料元素,(2) 存在唯一的一個被稱

線性儲存結構

2.3.1 線性表的鏈式儲存結構——連結串列 連結串列: 1.每個節點中除資料域外,設定了一個指標域,用以指向其後繼節點,這樣構成的連結表稱為線性單向連結串列,簡稱單鏈表。 2.每個節點中除資料域外,設定兩個指標域,分別用以指向其前驅節點和

3.線性儲存結構————靜態連結串列C語言和C++完整解析

目錄 1.靜態連結串列的概念 因為有些語言沒有指標,所以難以實現普通連結串列,靜態連結串列就是用來解決這一問題的有力工具,靜態連結串列使用陣列來實現連結串列。靜態連結串列用遊標來代替普通連結串列的指標域,並且用下標代替普通連結串列的結點

儲存結構單鏈

1.線性表的鏈式儲存結構 線性表的鏈式儲存結構允許資料元素存在任意未被佔用的記憶體空間,因為線上性表的鏈式儲存結構中,除了儲存資料元素相關的資料資訊之外,還儲存了資料元素的後繼元素儲存地址,這樣通過當前資料元素很容易找到下一個資料元素。 鏈式儲存結構中,存取一個數據元素內容資訊和直接後繼的儲存位置的結構稱

線性儲存結構從建插入到 刪除銷燬

檔案1    list.c#include<stdio.h> #include"list.h" #include<stdlib.h> #include<string.h> /* 函式名 creatList; 功能 建立連結串列 申請空間

單鏈基本操作的C語言實現儲存結構

#include<stdio.h> #include<stdlib.h> typedef int DataType; typedef struct Node{ DataType data; struct Node *next; }

走進資料結構和演算法c++版3——線性儲存結構

線性表的鏈式儲存結構   我們知道線性表的順序儲存結構在插入和刪除操作時需要移動大量的資料,他們的時間複雜度為O(n)O(n)。當我們需要經常插入和刪除資料時,順序儲存結構就不適用了,這時我們就需要用到線性表的鏈式儲存結構。   線性表的鏈式儲存結構的特點是

線性儲存結構

鏈式儲存定義: 為了表示每個資料元素與其直接後繼元素之間的邏輯關係,每個元素除了儲存本身的資訊外,還需要儲存指示其直接後繼的資訊。 單鏈表包括: 表頭結點:連結串列中的第一個結點,包含指向第一個資料元素的指標以及連結串列自身的一些資訊。 資料結點:連結串列中代表資料元素的

C語言實現線性儲存結構

線性表的鏈式儲存結構 特點 結點除自身的資訊域外,還有表示關聯資訊的指標域。因此,鏈式儲存結構的儲存密度小、儲存空間利用率低。 在邏輯上相鄰的結點在物理上不必相鄰,因此,不可以隨機存取,只能順序存取。 插入和刪除操作方便靈活,不必移動結點只需修改結點

線性佇列的儲存結構

一、順序儲存結構與鏈式儲存結構的區別        順序儲存就是從記憶體中取出一段連續地址的空間,將資料依次連續的儲存在這段空間中。而鏈式儲存結構是指資料儲存在記憶體中的地址是離散的,以資料節點為單