在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C語言-鏈表(單向鏈表、雙向鏈表)

DS小龍哥-嵌入式技術 ? 來源:DS小龍哥-嵌入式技術 ? 作者:DS小龍哥-嵌入式技 ? 2022-09-09 11:30 ? 次閱讀

1. 鏈表結構介紹

在前面章節已經學習了數組的使用,數組的空間是連續空間,數組的大小恒定的,在很多動態數據存儲的應用場景下,使用不方便;而這篇文章介紹的鏈表結構,支持動態增加節點,釋放節點,比較適合存儲動態數據的應用場景,而且鏈表的空間是存儲在堆上面的,可以動態分配,釋放。從效率上來講,數組的空間是連續的,查詢、讀取數據數組占優勢;鏈表的優勢在于節點可以動態增加、動態刪除,刪除支持任意位置的節點刪除。

特點:

數組的空間是連續的,可以直接通過[]下標訪問。

鏈表的節點是不連續的,需要通過每個節點的指針,來找到上一個節點或者下一個節點的地址。

鏈表的每個節點就是一個結構體變量,節點里有一個或者兩個指針,可以保存上一個節點和下一個節點的地址,方便遍歷鏈表,刪除、插入節點時定位位置。

image-20211203094458762

2. 案例: 單向鏈表的創建與使用

下面例子采用函數封裝的形式編寫,每個功能都使用子函數實現。

image-20211203095248628image-20211203095310341

實現的功能如下:

  1. 初始化鏈表頭
  2. 插入節點的函數(鏈表任意位置插入,鏈表尾插入)
  3. 刪除節點的函數(鏈表任意位置刪除、鏈表尾刪除)
  4. 遍歷鏈表,輸出鏈表里的所有信息
#include 
#include 
?
//定義鏈表節點的結構體
struct app
{
  int a;
  struct app *next; //能保存結構體的地址
};
?
struct app *list_head=NULL; //鏈表的頭指針
?
void list_print(struct app *head);
struct app *list_HeadInit(struct app *head);
void list_add(int a,struct app *head);
void list_del(int a,struct app *head);
?
int main()
{
  //1. 初始化鏈表頭
  list_head=list_HeadInit(list_head);
  //2. 在鏈表尾插入數據
  list_add(10,list_head);
  list_add(11,list_head);
  list_add(12,list_head);
  list_add(13,list_head);
  //3. 刪除節點
  list_del(11,list_head);
  //4. 輸出鏈接節點里的數據
  list_print(list_head);
  return 0;
}
?
/*
函數功能: 初始化鏈表頭--給鏈表頭申請空間
*/
struct app *list_HeadInit(struct app *head)
{
  if(head==NULL) //沒有空間
   {
    //1. 申請鏈表頭空間
    head=malloc(sizeof(struct app));
    //2. 初始化鏈表頭
    head->next=NULL;
   }
  return head;
}
?
/*
函數功能: 在鏈表尾插入數據
int a  插入的數據值
struct app *head  鏈表頭
*/
void list_add(int a,struct app *head)
{
  struct app *new_p=NULL;
  struct app *next_p=head;
  struct app *tmp_p; //保存上一個節點的地址
  //1.申請空間并給空間成員賦值
  new_p=malloc(sizeof(struct app));
  new_p->a=a;
  new_p->next=NULL;
?
  //2. 找到鏈表尾
  while(next_p!=NULL)
   {
    tmp_p=next_p;
    next_p=next_p->next; //指針指向下一個節點
   }
?
  //3. 插入新節點--鏈接結尾
  tmp_p->next=new_p;
}
?
/*
函數功能: 遍歷輸出鏈接里的所有數據
*/
void list_print(struct app *head)
{
  struct app *next_p=head;
  int cnt=0;
  if(head!=NULL)
   {
    while(next_p->next!=NULL)
     {
      next_p=next_p->next;
      printf("鏈表節點[%d]:a=%d\n",cnt++,next_p->a);
     }
   }
}
?
/*
函數功能:鏈表的刪除--按照指定的數據刪除
*/
void list_del(int a,struct app *head)
{
  struct app *next_p=head;
  struct app *tmp_p; //保存上一個節點的地址
  //1. 找到要刪除的鏈表
  if(next_p!=NULL)
   {
    while(next_p->next!=NULL)
     {
      tmp_p=next_p; //保存上一個節點的地址
      next_p=next_p->next; //獲取有效節點的地址
      if(next_p->a==a) //判斷是否需要刪除
       {
        tmp_p->next=next_p->next;
        free(next_p);
       }
     }
   }
}
復制代碼

3. 案例: 單向循環鏈表

代碼直接在上面的案例2例子上改造的,區別就是尾結點指向了頭結點而不是NULL。

#include 
#include 
?
//定義鏈表節點的結構體
struct app
{
  int a;
  struct app *next; //能保存結構體的地址
};
?
struct app *list_head=NULL; //鏈表的頭指針
?
void list_print(struct app *head);
struct app *list_HeadInit(struct app *head);
void list_add(int a,struct app *head);
void list_del(int a,struct app *head);
?
int main()
{
  //1. 初始化鏈表頭
  list_head=list_HeadInit(list_head);
  //2. 在鏈表尾插入數據
  list_add(10,list_head);
  list_add(11,list_head);
  list_add(12,list_head);
  list_add(13,list_head);
  //3. 刪除節點
  list_del(11,list_head);
  //4. 輸出鏈接節點里的數據
  list_print(list_head);
  return 0;
}
?
/*
函數功能: 初始化鏈表頭--給鏈表頭申請空間
*/
struct app *list_HeadInit(struct app *head)
{
  if(head==NULL) //沒有空間
   {
    //1. 申請鏈表頭空間
    head=malloc(sizeof(struct app));
    //2. 初始化鏈表頭
    head->next=head;
   }
  return head;
}
?
/*
函數功能: 在鏈表尾插入數據
int a  插入的數據值
struct app *head  鏈表頭
*/
void list_add(int a,struct app *head)
{
  struct app *new_p=NULL;
  struct app *next_p=head;
  struct app *tmp_p; //保存上一個節點的地址
  //1.申請空間并給空間成員賦值
  new_p=malloc(sizeof(struct app));
  new_p->a=a;
  new_p->next=head;
?
  //2. 找到鏈表尾
  if(head!=NULL)
   {
    if(next_p->next==head) //表示第一次插入節點
     {
      next_p->next=new_p;
      //head ----<節點1>---head
     }
    else
     {
      while(next_p->next!=head)
       {
        next_p=next_p->next; //指針指向下一個節點
       }
      //3. 插入新節點--鏈接結尾
      next_p->next=new_p;
     }  
   } 
}
?
/*
函數功能: 遍歷輸出鏈接里的所有數據
*/
void list_print(struct app *head)
{
  struct app *next_p=head;
  int cnt=0;
  if(head!=NULL)
   {
    printf("頭地址: %#x\n",next_p); //頭
    printf("第一個節點地址:%#x\n",next_p->next); //下一個節點地址
    printf("第二個節點地址:%#x\n",next_p->next->next); //下下一個節點地址
    printf("第三個節點地址:%#x\n",next_p->next->next->next);
    printf("第四個節點地址:%#x\n",next_p->next->next->next->next);
  
    while(next_p->next!=head)
     {
      next_p=next_p->next;
      printf("鏈表節點[%d]:a=%d\n",cnt++,next_p->a);
     }
   }
}
?
/*
函數功能:鏈表的刪除--按照指定的數據刪除
*/
void list_del(int a,struct app *head)
{
  struct app *next_p=head;
  struct app *tmp_p; //保存上一個節點的地址
  //1. 找到要刪除的鏈表
  if(next_p!=NULL)
   {
    while(next_p->next!=head)
     {
      tmp_p=next_p; //保存上一個節點的地址
      next_p=next_p->next; //獲取有效節點的地址
      if(next_p->a==a) //判斷是否需要刪除
       {
        tmp_p->next=next_p->next;
        free(next_p);
       }
     }
   }
}
復制代碼

4. 案例: 創建雙向鏈表循環,實現插入、刪除、遍歷

雙向鏈表在每個節點里新增加了一個指針,用于保存上一個節點的地址,現在的節點里一個用兩個指針,一個保存上一個節點的地址,一個保存下一個節點的地址。

#include 
#include 
?
//定義鏈表節點的結構體
struct app
{
  int a;
  struct app *next; //下一個節點地址
  struct app *prev; //前一個節點地址
};
?
//全局變量聲明區域
struct app *list_head=NULL; //鏈表的頭指針
?
//函數聲明
struct app *List_HeadInit(struct app *head);
void list_add(int a,struct app *head);
void list_print(struct app *head);
void list_del(int a,struct app *head);
?
int main()
{
  /*1. 初始化鏈表*/
  list_head=List_HeadInit(list_head);
  /*2. 添加鏈表節點*/
  list_add(10,list_head);
  list_add(11,list_head);
  list_add(12,list_head);
  list_add(13,list_head);
  list_add(14,list_head);
  /*3.刪除指定節點*/
  list_del(12,list_head);
  /*4. 遍歷輸出所有節點信息*/
  list_print(list_head);
  return 0;
}
?
/*
函數功能: 創建鏈表頭
*/
struct app *List_HeadInit(struct app *head)
{
  if(head==NULL)
   {
    head=malloc(sizeof(struct app));
    head->a=0;
    head->next=head;
    head->prev=head;
   }
  return head;
}
?
/*
函數功能: 添加數據-鏈表尾添加數據
*/
void list_add(int a,struct app *head)
{
  struct app *next_p=head;
  struct app *new_p=NULL;
  /*1. 申請新的節點*/
  new_p=malloc(sizeof(struct app));
  new_p->a=a;
  new_p->next=head;
  /*2. 完成新節點的添加*/
  //遍歷鏈表
  while(next_p->next!=head)
   {
    next_p=next_p->next;
   }
  //添加新節點
  new_p->prev=next_p;
  next_p->next=new_p;
  //修改鏈表頭的上一個節點地址
  head->prev=new_p;
}
?
/*
函數功能:輸出鏈表里的所有數據
*/
void list_print(struct app *head)
{
  struct app *next_p=head;
  int cnt=0;
  /*1. 順向遍歷*/
  while(next_p->next!=head)
   {
    next_p=next_p->next;
    printf("節點[%d]:%d\n",cnt++,next_p->a);
   }
  /*2. 反向遍歷*/
  next_p=head;
  while(next_p->prev!=head)
   {
    next_p=next_p->prev;
    printf("節點[%d]:%d\n",cnt--,next_p->a);
   }
}
?
/*
函數功能:刪除鏈表里的指定節點
*/
void list_del(int a,struct app *head)
{
  struct app *next_p=head;
  struct app *tmp_p=NULL;
  while(next_p->next!=head)
   {
    tmp_p=next_p; //保存上一個節點的地址
    next_p=next_p->next;
    if(next_p->a==a)
     {
      //方式1
      tmp_p->next=tmp_p->next->next;
      tmp_p->next->prev=tmp_p;
?
      //方式2
      //tmp_p->next=next_p->next;
      //next_p->next->prev=tmp_p;
      
      //printf("%d\n",tmp_p->a); //11
      //printf("%d\n",tmp_p->next->a); //13
      //printf("%d\n",next_p->next->prev->a); //11
      free(next_p);
      break;
     }
   }
}

審核編輯 黃昊宇
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5093

    文章

    19178

    瀏覽量

    307708
  • C語言
    +關注

    關注

    180

    文章

    7614

    瀏覽量

    137727
收藏 人收藏

    評論

    相關推薦

    C語言實現動態鏈表的建立

    上期講解了靜態鏈表的實例,但是靜態鏈表建立的節點數量有限,畢竟是手工建立,難免也會出問題, 所以這期講講怎么使用動態的方式建立鏈表,也就是 動態鏈表 !
    發表于 01-13 15:16 ?1538次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>實現動態<b class='flag-5'>鏈表</b>的建立

    C語言算法題:反轉一個單向鏈表

    鏈表是編程學習的一個難點。其實,在C語言編程以及單片機裸機開發中,鏈表運用并不多。但是如果想提升嵌入式技能水平或收入水平,可以考慮深入嵌入式系統層面(如參與操作系統設計、深入學習新的操
    發表于 06-21 11:07 ?913次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>算法題:反轉一個<b class='flag-5'>單向</b><b class='flag-5'>鏈表</b>

    C語言鏈表知識點(2)

    C語言鏈表知識點(2)
    發表于 08-22 10:38 ?353次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>鏈表</b>知識點(2)

    C語言單向鏈表

    本帖最后由 snowmay001 于 2016-5-22 15:57 編輯 lianbiao.cpp/* 練習使用鏈表:創建鏈表、遍歷鏈表、查找節點、添加節點、刪除節點*/#include
    發表于 05-22 15:53

    C語言鏈表

    C語言鏈表,,,
    發表于 11-07 17:19

    C語言玩轉鏈表

    C語言是必學的一個課程,不管你是單片機還是嵌入式物聯網,都是基礎,所以還是要好好學習的今天推薦的資料是關于C語言鏈表的資料我自己看了一下主要
    發表于 11-13 13:50

    玩轉C語言鏈表-鏈表各類操作詳解

    ,它稱為“表尾”,它的地址部分放一個“NULL”(表示“空地址”),鏈表到此結束?! ?b class='flag-5'>鏈表的各類操作包括:學習單向鏈表的創建、刪除、 插入(無序、有序)、輸出、 排序(選擇、插入、冒泡
    發表于 09-18 13:30

    如何在C語言中去創建一種雙向鏈表

    雙向鏈表的結構是由哪些部分組成的?如何在C語言中去創建一種雙向鏈表呢?
    發表于 12-24 06:22

    C語言實現單鏈表舉例

    所謂鏈表,就是用一組任意的存儲單元存儲線性表元素的一種數據結構。鏈表又分為單鏈表雙向鏈表和循環鏈表
    發表于 07-11 16:40 ?87次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>實現單<b class='flag-5'>鏈表</b>舉例

    C加加建立動態鏈表

    C加加建立動態鏈表利用C語言c++編寫程序
    發表于 11-19 13:43 ?0次下載

    C語言鏈表相關資料下載

    C語言鏈表相關資料
    發表于 03-08 10:47 ?5次下載

    了解Linux通用的雙向循環鏈表

    在linux內核中,有一種通用的雙向循環鏈表,構成了各種隊列的基礎。鏈表的結構定義和相關函數均在include/linux/list.h中,下面就來全面的介紹這一鏈表的各種API。
    發表于 05-07 10:44 ?694次閱讀

    雙向循環鏈表的創建

    需要注意的是,雖然雙向循環鏈表成環狀,但本質上還是雙向鏈表,因此在雙向循環鏈表中,依然能夠找到頭
    的頭像 發表于 05-24 16:27 ?2147次閱讀

    C語言_鏈表總結

    本篇文章介紹C語言鏈表相關知識點,涉及鏈表的創建、單向鏈表、循環
    的頭像 發表于 08-14 09:53 ?1831次閱讀

    鏈表和雙鏈表的區別在哪里

    。 上面的三幅圖對于理解鏈表的插入、刪除很重要,看代碼的時候要對著看。 實際中經常使用的一般為帶頭雙向循環鏈表,下面是一個雙向循環鏈表的 d
    的頭像 發表于 07-27 11:20 ?1765次閱讀
    單<b class='flag-5'>鏈表</b>和雙<b class='flag-5'>鏈表</b>的區別在哪里
    主站蜘蛛池模板: 天天做爽夜夜做爽 | 色综合色综合色综合 | xxxxx69日本老师hd | 成人黄色在线 | 亚洲成人免费网站 | 91亚洲国产成人久久精品网站 | 丁香狠狠色婷婷久久综合 | 欧美黄色大全 | 国产91久久最新观看地址 | 欧美久久天天综合香蕉伊 | 四虎看片 | 久操视频在线免费观看 | 爽好舒服快小柔小说 | 高h肉肉视频在线播放观看 高黄视频 | 欧美日本一区二区三区生 | 日本成人免费 | 特别毛片 | 欧美系列在线播放 | 久久精品国产2020观看福利色 | 夜夜操伊人 | 国产三级在线观看 | 奇米影视亚洲狠狠色777不卡 | 久久影视免费体验区午夜啪啪 | 亚洲欧洲一区二区三区在线 | 伊人网网| 国产精品9999久久久久仙踪林 | 黄网站色视频 | 一区二区三区四区视频 | 色视频免费国产观看 | 免费毛片网站在线观看 | 天天综合天天综合色在线 | 年轻护士3的滋味 | 欧美一卡二卡科技有限公司 | 亚洲欧洲一区二区三区在线观看 | 婷婷狠狠 | 天天干天天骑 | 色综合日韩 | 一级特级aaaa毛片免费观看 | 亚洲欧美一区二区三区图片 | 特级毛片a级毛免费播放 | 日韩污|