SlideShare a Scribd company logo
1 of 6
Download to read offline
静态链表

  在线性表这一章,除了正常的顺序表和链表之外,还经常会考到静态链表。其实,静态
也没有什么神秘的,和普通的用指针型描述的线性链表相比,静态链表是通过(一维)数组
来描述线性链表。
  静态链表:首先它是个数组,这个数组相当于一个块可以由你自由支配的内
存空间
  这块内存空间的首地址是 SLinkList[0]
  每个链表需要保存的只是它头结点在这个数组是第几个元素就可以了。
  所有的内存分配和回收都是头结点的下一个进行操作

//线性表的静态单链表存储结构
#define MAXSIZE 100;
typedef struct{
 ElemType data;
 int cur;
}component,SLinkList[MAXSIZE];




特点:
1.在静态空间里实现动态数据结构
2.两个链表:数据链表和空闲空间链表
3.没有现成的空间管理函数
上面的特点提到了几个重要的问题, 既然是在静态空间里实现动态数据结构,需要辨明数组
中哪些分量未被使用, 解决的办法是将所有未被使用的以及被删除的分量用游标链成一个备
用的链表,每当进行插入时从备用链表上取得第一个结点作为插入的新结点;反之,在删除
时将从链表中删除的结点链接到备用链表上。 这里的对结点插入和删除需要的空间管理函数
时需要自定义的,要不然你说我要一个结点,谁给你啊,你不要了一个结点,别人谁要啊。
注:关于这点,在本文最后摘录了关于内存管理的一些知识,以了解内存分配和释放过程。
请先浏览本部分,再继续。

⑴初始化
void InitSpace_SL(SlinkList &space)
{∥将一维数组 space 中各分量链成一个备用链表,
  //space[0].cur 为头指针,"0"表示空指针
 for(i = 0; i < MAXSIZE-1; ++i )

      1
space[i].cur = i+1;
    space[MAXSIZE-1]=0;
}∥InitSpace_SL

⑵申请建立一个结点
int Malloc_SL(SlinkList &space)
{      ∥若备用空间链表非空,则返回分配的结点下标,否则返回 0
    i = space[0].cur;
    if (space[0].cur)
        space[0].cur = space[i].cur;
    return i;
}∥Malloc_SL

⑶回收一个结点
void Free_SL(SlinkList &space, int k)
∥将下标为 k 的空闲结点收回到备用链表
{space[k].cur = space[0].cur;
  space[0].cur = k;
}∥Free_SL

在了解了上面的几个操作之后,用静态链表解决集合的运算(A-B)∪(B-A)问题。
算法:
void difference(SlinkList &space, int &S)
{∥依次输入集合 A 和 B 的元素,在一维数组 space 中建立表示集合(A-B)∪(B-A)
∥的静态链表,S 为其头指针.假设备用空间足够大,space[0].cur 为其头指针.
 InitSpace_SL(space);                                   ∥初始化备用空间
 S= Malloc_SL(space);                                   ∥生成 S 的头结点
 r= S;                                                   ∥r 指向 S 的当前最后结点
 scanf(m,n);                                             ∥输入 A 和 B 的元素个数
 for(j=1; j<=m; ++j)                                   ∥建立集合 A 的链表
  { i =Malloc_SL(space);                               ∥分配结点
      scanf(space[i].data);                              ∥输入 A 的元素值
      space[r].cur=i;r=i;                                 ∥插入到表尾
  }∥for
space[r].cur=0;                                       ∥尾结点的指针为空
for( j=1; j<=n; ++j)         ∥依次输入 B 的元素,若不在当前表中,则插入,否则删除
 {scanf(b); p=S; k=space[S].cur;            ∥k 指向集合 A 中第一个结点
    while( k!=space[r].cur&&space[k].data!=b)
        { p=k; k=space[k].cur;   }              ∥当前表中查找
      if (k= =space[r].cur)
       {                      ∥当前表中不存在该元素,插入在 r 所指结点之后,且 r 的位置不变
            i =Malloc_SL(space);           space[i].data =b;
           space[i].cur =space[r].cur; space[r].cur =i;
           }∥if

           2
else{    space[p].cur =space[k].cur;    ∥该元素已在表中,删除之
                    Free_SL(space,k);
                   if(r==k)   r=p;                 ∥若删除的是尾元素,则需修改尾指针
               }∥else
  }∥for
}∥difference


例:已知集合 A={1,2,5,8,9,3},B={4,2,7,3,1},画出利用静态链表计算(A-B)
∪(B-A)后的示意图。  (第一次测验题)

解:
InitSpace_SL(space);

  0           1        2       3        4     5    6    7         8     9    10

  1           2        3       4        5     6    7    8         9     10   0/11

S= Malloc_SL(space);
  0     1    2     3                    4     5    6    7         8     9    10

  2           2        3       4        5     6    7    8         9     10   0/11

                   S
集合 A:
 0    1                2       3        4     5    6    7         8     9    10
                       1       2        5     8    9    3
  8           2        3       4        5     6    7    0         9     10   0/11

                   S                                          r
插入 4:∥当前表中不存在该元素,插入在 r 所指结点之后,且 r 的位置不变
if (k= =space[r].cur)//r=7,k=0
      { i =Malloc_SL(space);
      // i = space[0].cur;          // i=8
      // if (space[0].cur)
      // space[0].cur = space[i].cur;//8->9
      // return i;
         space[i].data =b;                //b=4
        space[i].cur =space[r].cur; //->0
        space[r].cur =i;                  //0->8
        }∥if
  0           1        2       3        4     5    6    7          8    9    10
                       1       2        5     8    9    3          4
8->9          2        3       4        5     6    7   0->8       ->0   10   0/11

         3
删除 2:∥该元素已在表中,删除之,且删除的不是尾元素,不需修改尾指针
{   //p=2,=3
space[p].cur =space[k].cur;        ∥space[2].cur=space[3].cur=4
                 Free_SL(space,k);
// space[k].cur = space[0].cur; //4->9
// space[0].cur = k;               //9->3
                   if(r==k)   r=p;                     ∥若删除的是尾元素,则需修改尾指针
               }∥else


    0       1        2    3            4           5   6        7     8   9    10
                     1    2            5           8   9        3     4
9->3        2       3->4 4->9          5           6   7        8     0   10   0/11

插入 7://当前表中不存在该元素,插入在 r 所指结点之后,且 r 的位置不变
if (k= =space[r].cur)//r=7,得到 k=8
      {
         i =Malloc_SL(space);
      // i = space[0].cur;           // i=3
      // if (space[0].cur)
      // space[0].cur = space[i].cur;//3->9
      // return i;                         //i=3
        space[i].data =b;//b=7
        space[i].cur =space[r].cur;//9->8
        space[r].cur =i;//8->3
        }∥if


    0       1         2        3       4           5   6        7     8   9    10
                      1        7       5           8   9        3     4
3->9        2         4       9->8     5           6   7       8->3   0   10   0/11

删除 3:∥该元素已在表中,删除之,且删除的是尾元素,需修改尾指针
{   //p=6,k=7
space[p].cur =space[k].cur;        ∥space[6].cur=space[7].cur=3
                 Free_SL(space,k);
// space[k].cur = space[0].cur; //3->9
// space[0].cur = k; 9->7
                   if(r==k)   r=p;                 ∥删除的是尾元素,修改尾指针,r->6
               }∥else
    0       1         2        3       4           5   6        7     8   9    10
                      1        7       5           8   9              4
9->7        2         4        8       5           6   3       3->9   0   10   0/11
                                                           r

删除 1:∥该元素已在表中,删除之,且删除的不是尾元素,不需修改尾指针
        4
{   //p=1,k=2
space[p].cur =space[k].cur;      ∥space[1].cur=space[2].cur=4
                 Free_SL(space,k);
// space[k].cur = space[0].cur;
// space[0].cur = k;
                if(r==k)   r=p;                 ∥若删除的是尾元素,则需修改尾指针
            }∥else


    0       1      2        3     4       5       6       7     8   9    10
                            7     5       8       9             4
7->2        4    4->7       8     5       6       3       9     0   10   0/11

                                                      r
最终结果:

    0       1      2        3     4       5       6       7     8   9    10
                            7     5       8       9             4
    2       4      7        8     5       6       3       9     0   10   0/11




附:内存动态申请

怎么去理解这个内存分配和释放过程呢?先看下面这段对话:
万岁爷:爱卿,你为朕立下了汗马功劳,想要何赏赐啊?
某功臣:万岁,黄金白银,臣视之如粪土。臣年岁已老,欲告老还乡。臣乞良田千亩
以荫后世,别无他求。
万岁爷:爱卿,你劳苦功高,却仅要如此小赏,朕今天就如你所愿。户部刘侍郎,查
看湖广一带是否还有千亩上等良田未曾封赏。
刘侍郎:长沙尚有五万余亩上等良田未曾封赏。
万岁爷:在长沙拨良田千亩封赏爱卿。爱卿,良田千亩,你欲何用啊?
某功臣:谢万岁。长沙一带,适合种水稻,臣想用来种水稻。种水稻需要把田分为一
亩一块,方便耕种。
。。。。
不要莫名其妙,其实上面这段小小的对话,就是malloc 的使用过程。malloc 是一个函
数,专门用来从堆上分配内存。使用malloc 函数需要几个要求:
内存分配给谁?这里是把良田分配给某功臣。
分配多大内存?这里是分配一千亩。
是否还有足够内存分配?这里是还有足够良田分配。
内存的将用来存储什么格式的数据,即内存用来做什么?这里是用来种水稻,需要把田

        5
分成一亩一块。
分配好的内存在哪里?这里是在长沙。
如果这五点都确定,那内存就能分配。下面先看malloc 函数的原型:
(void *)malloc(int size)
malloc 函数的返回值是一个void 类型的指针,参数为int 类型数据,即申请分配的内存
大小,单位是byte。内存分配成功之后,malloc 函数返回这块内存的首地址。你需要一个
指
针来接收这个地址。但是由于函数的返回值是void *类型的,所以必须强制转换成你所接收
的类型。也就是说,这块内存将要用来存储什么类型的数据。比如:
char *p = (char *)malloc(100);
在堆上分配了100 个字节内存,返回这块内存的首地址,把地址强制转换成char *类型后赋
给char *类型的指针变量p。同时告诉我们这块内存将用来存储char 类型的数据。也就是说
你只能通过指针变量p 来操作这块内存。这块内存本身并没有名字,对它的访问是匿名访
问。
上面就是使用malloc 函数成功分配一块内存的过程。但是,每次你都能分配成功吗?
不一定。上面的对话,皇帝让户部侍郎查询是否还有足够的良田未被分配出去。使用malloc
函数同样要注意这点:如果所申请的内存块大于目前堆上剩余内存块(整块),则内存分配
会失败,函数返回NULL。注意这里说的“堆上剩余内存块”不是所有剩余内存块之和,因
为malloc 函数申请的是连续的一块内存。
既然malloc 函数申请内存有不成功的可能,那我们在使用指向这块内存的指针时,必
须用 if(NULL != p)语句来验证内存确实分配成功了。
既然有分配,那就必须有释放。不然的话,有限的内存总会用光,而没有释放的内存
却在空闲。与malloc 对应的就是free 函数了。free 函数只有一个参数,就是所要释放的
内
存块的首地址。比如上例:
free(p);
free 函数看上去挺狠的,但它到底作了什么呢?其实它就做了一件事:斩断指针变量与
这块内存的关系。比如上面的例子,我们可以说malloc 函数分配的内存块是属于p 的,因
为我们对这块内存的访问都需要通过p 来进行。free 函数就是把这块内存和p 之间的所有
关系斩断。从此p 和那块内存之间再无瓜葛。至于指针变量p 本身保存的地址并没有改变,
但是它对这个地址处的那块内存却已经没有所有权了。那块被释放的内存里面保存的值也
没有改变,只是再也没有办法使用了。

--摘自 陈正冲《C 语言深度剖析》




   6

More Related Content

What's hot

Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Androidkoji lin
 
Java 開發者的函數式程式設計
Java 開發者的函數式程式設計Java 開發者的函數式程式設計
Java 開發者的函數式程式設計Justin Lin
 
新數學UPUP學測講義
新數學UPUP學測講義新數學UPUP學測講義
新數學UPUP學測講義lungtengtech
 
第10章 代码优化
第10章 代码优化第10章 代码优化
第10章 代码优化tjpucompiler
 
【稱霸】高中數學(1~4冊)總複習講義
【稱霸】高中數學(1~4冊)總複習講義【稱霸】高中數學(1~4冊)總複習講義
【稱霸】高中數學(1~4冊)總複習講義lungtengtech
 
龍騰數學統測必考高頻率題型
龍騰數學統測必考高頻率題型龍騰數學統測必考高頻率題型
龍騰數學統測必考高頻率題型lungtengtech
 
計算機
計算機計算機
計算機maolins
 
1.3整式及其运算
1.3整式及其运算1.3整式及其运算
1.3整式及其运算zhengweimin83
 
【逆轉勝】數學學測總複習講義
【逆轉勝】數學學測總複習講義【逆轉勝】數學學測總複習講義
【逆轉勝】數學學測總複習講義lungtengtech
 
数据结构复习笔记 字符串模式匹配算(Kmp)
数据结构复习笔记 字符串模式匹配算(Kmp)数据结构复习笔记 字符串模式匹配算(Kmp)
数据结构复习笔记 字符串模式匹配算(Kmp)mengyingchina
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片kao kuo-tung
 

What's hot (18)

Ch9 教學
Ch9 教學Ch9 教學
Ch9 教學
 
Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Android
 
Java 開發者的函數式程式設計
Java 開發者的函數式程式設計Java 開發者的函數式程式設計
Java 開發者的函數式程式設計
 
Ch10 範例
Ch10 範例Ch10 範例
Ch10 範例
 
新數學UPUP學測講義
新數學UPUP學測講義新數學UPUP學測講義
新數學UPUP學測講義
 
第10章 代码优化
第10章 代码优化第10章 代码优化
第10章 代码优化
 
【稱霸】高中數學(1~4冊)總複習講義
【稱霸】高中數學(1~4冊)總複習講義【稱霸】高中數學(1~4冊)總複習講義
【稱霸】高中數學(1~4冊)總複習講義
 
龍騰數學統測必考高頻率題型
龍騰數學統測必考高頻率題型龍騰數學統測必考高頻率題型
龍騰數學統測必考高頻率題型
 
計算機
計算機計算機
計算機
 
Hi Haskell
Hi HaskellHi Haskell
Hi Haskell
 
1.3整式及其运算
1.3整式及其运算1.3整式及其运算
1.3整式及其运算
 
【逆轉勝】數學學測總複習講義
【逆轉勝】數學學測總複習講義【逆轉勝】數學學測總複習講義
【逆轉勝】數學學測總複習講義
 
Appendix B 教學
Appendix B 教學Appendix B 教學
Appendix B 教學
 
数据结构复习笔记 字符串模式匹配算(Kmp)
数据结构复习笔记 字符串模式匹配算(Kmp)数据结构复习笔记 字符串模式匹配算(Kmp)
数据结构复习笔记 字符串模式匹配算(Kmp)
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片
 
Ppt 120-126
Ppt 120-126Ppt 120-126
Ppt 120-126
 
Ch9
Ch9Ch9
Ch9
 
Appendix B 範例
Appendix B 範例Appendix B 範例
Appendix B 範例
 

Similar to 数据结构复习笔记 静态链表

第三章 栈和队列
第三章 栈和队列第三章 栈和队列
第三章 栈和队列Wang Yizhe
 
第三章 栈和队列(新)
第三章 栈和队列(新)第三章 栈和队列(新)
第三章 栈和队列(新)Wang Yizhe
 
ncuma_pylab.pptx
ncuma_pylab.pptxncuma_pylab.pptx
ncuma_pylab.pptxNCU MCL
 
JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1Sheng-Han Su
 
Python learn guide
Python learn guidePython learn guide
Python learn guiderobin yang
 
221013 GDSC Kotlin Basics.pptx
221013 GDSC Kotlin Basics.pptx221013 GDSC Kotlin Basics.pptx
221013 GDSC Kotlin Basics.pptxNCUDSC
 
第6章 自底向上的lr分析法
第6章 自底向上的lr分析法第6章 自底向上的lr分析法
第6章 自底向上的lr分析法tjpucompiler
 
龍騰[掌握]數學A複習講義
龍騰[掌握]數學A複習講義龍騰[掌握]數學A複習講義
龍騰[掌握]數學A複習講義lungtengtech
 

Similar to 数据结构复习笔记 静态链表 (10)

第三章 栈和队列
第三章 栈和队列第三章 栈和队列
第三章 栈和队列
 
第三章 栈和队列(新)
第三章 栈和队列(新)第三章 栈和队列(新)
第三章 栈和队列(新)
 
ncuma_pylab.pptx
ncuma_pylab.pptxncuma_pylab.pptx
ncuma_pylab.pptx
 
Delta (rostock)
Delta (rostock)Delta (rostock)
Delta (rostock)
 
JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1JavaScript 快速複習 2017Q1
JavaScript 快速複習 2017Q1
 
Python learn guide
Python learn guidePython learn guide
Python learn guide
 
221013 GDSC Kotlin Basics.pptx
221013 GDSC Kotlin Basics.pptx221013 GDSC Kotlin Basics.pptx
221013 GDSC Kotlin Basics.pptx
 
Scilab Chap1
Scilab Chap1Scilab Chap1
Scilab Chap1
 
第6章 自底向上的lr分析法
第6章 自底向上的lr分析法第6章 自底向上的lr分析法
第6章 自底向上的lr分析法
 
龍騰[掌握]數學A複習講義
龍騰[掌握]數學A複習講義龍騰[掌握]數學A複習講義
龍騰[掌握]數學A複習講義
 

More from mengyingchina

哈佛幸福课[升级版]
哈佛幸福课[升级版]哈佛幸福课[升级版]
哈佛幸福课[升级版]mengyingchina
 
数据结构复习笔记 图的遍历及连通性问题
数据结构复习笔记 图的遍历及连通性问题数据结构复习笔记 图的遍历及连通性问题
数据结构复习笔记 图的遍历及连通性问题mengyingchina
 
数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作
数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作
数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作mengyingchina
 
数据结构复习笔记 拓扑排序Topological+sort
数据结构复习笔记 拓扑排序Topological+sort数据结构复习笔记 拓扑排序Topological+sort
数据结构复习笔记 拓扑排序Topological+sortmengyingchina
 
数据结构复习笔记 关键路径+Critical+paths
数据结构复习笔记 关键路径+Critical+paths数据结构复习笔记 关键路径+Critical+paths
数据结构复习笔记 关键路径+Critical+pathsmengyingchina
 
数据结构复习笔记 树和二叉树
数据结构复习笔记 树和二叉树数据结构复习笔记 树和二叉树
数据结构复习笔记 树和二叉树mengyingchina
 

More from mengyingchina (8)

哈佛幸福课[升级版]
哈佛幸福课[升级版]哈佛幸福课[升级版]
哈佛幸福课[升级版]
 
幸福课
幸福课幸福课
幸福课
 
数据结构复习笔记 图的遍历及连通性问题
数据结构复习笔记 图的遍历及连通性问题数据结构复习笔记 图的遍历及连通性问题
数据结构复习笔记 图的遍历及连通性问题
 
数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作
数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作
数据结构复习笔记 图的数组(邻接矩阵)存储表示及重要的基本操作
 
数据结构复习笔记 拓扑排序Topological+sort
数据结构复习笔记 拓扑排序Topological+sort数据结构复习笔记 拓扑排序Topological+sort
数据结构复习笔记 拓扑排序Topological+sort
 
数据结构复习笔记 关键路径+Critical+paths
数据结构复习笔记 关键路径+Critical+paths数据结构复习笔记 关键路径+Critical+paths
数据结构复习笔记 关键路径+Critical+paths
 
数据结构复习笔记 树和二叉树
数据结构复习笔记 树和二叉树数据结构复习笔记 树和二叉树
数据结构复习笔记 树和二叉树
 
文献综述
文献综述文献综述
文献综述
 

Recently uploaded

泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书jakepaige317
 
educ6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxeduc6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxmekosin001123
 
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...黑客 接单【TG/微信qoqoqdqd】
 
EDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxEDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxmekosin001123
 
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxEDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxmekosin001123
 
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制jakepaige317
 

Recently uploaded (6)

泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
 
educ6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxeduc6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptx
 
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
 
EDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxEDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptx
 
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxEDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
 
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
 

数据结构复习笔记 静态链表

  • 1. 静态链表 在线性表这一章,除了正常的顺序表和链表之外,还经常会考到静态链表。其实,静态 也没有什么神秘的,和普通的用指针型描述的线性链表相比,静态链表是通过(一维)数组 来描述线性链表。 静态链表:首先它是个数组,这个数组相当于一个块可以由你自由支配的内 存空间 这块内存空间的首地址是 SLinkList[0] 每个链表需要保存的只是它头结点在这个数组是第几个元素就可以了。 所有的内存分配和回收都是头结点的下一个进行操作 //线性表的静态单链表存储结构 #define MAXSIZE 100; typedef struct{ ElemType data; int cur; }component,SLinkList[MAXSIZE]; 特点: 1.在静态空间里实现动态数据结构 2.两个链表:数据链表和空闲空间链表 3.没有现成的空间管理函数 上面的特点提到了几个重要的问题, 既然是在静态空间里实现动态数据结构,需要辨明数组 中哪些分量未被使用, 解决的办法是将所有未被使用的以及被删除的分量用游标链成一个备 用的链表,每当进行插入时从备用链表上取得第一个结点作为插入的新结点;反之,在删除 时将从链表中删除的结点链接到备用链表上。 这里的对结点插入和删除需要的空间管理函数 时需要自定义的,要不然你说我要一个结点,谁给你啊,你不要了一个结点,别人谁要啊。 注:关于这点,在本文最后摘录了关于内存管理的一些知识,以了解内存分配和释放过程。 请先浏览本部分,再继续。 ⑴初始化 void InitSpace_SL(SlinkList &space) {∥将一维数组 space 中各分量链成一个备用链表, //space[0].cur 为头指针,"0"表示空指针 for(i = 0; i < MAXSIZE-1; ++i ) 1
  • 2. space[i].cur = i+1; space[MAXSIZE-1]=0; }∥InitSpace_SL ⑵申请建立一个结点 int Malloc_SL(SlinkList &space) { ∥若备用空间链表非空,则返回分配的结点下标,否则返回 0 i = space[0].cur; if (space[0].cur) space[0].cur = space[i].cur; return i; }∥Malloc_SL ⑶回收一个结点 void Free_SL(SlinkList &space, int k) ∥将下标为 k 的空闲结点收回到备用链表 {space[k].cur = space[0].cur; space[0].cur = k; }∥Free_SL 在了解了上面的几个操作之后,用静态链表解决集合的运算(A-B)∪(B-A)问题。 算法: void difference(SlinkList &space, int &S) {∥依次输入集合 A 和 B 的元素,在一维数组 space 中建立表示集合(A-B)∪(B-A) ∥的静态链表,S 为其头指针.假设备用空间足够大,space[0].cur 为其头指针. InitSpace_SL(space); ∥初始化备用空间 S= Malloc_SL(space); ∥生成 S 的头结点 r= S; ∥r 指向 S 的当前最后结点 scanf(m,n); ∥输入 A 和 B 的元素个数 for(j=1; j<=m; ++j) ∥建立集合 A 的链表 { i =Malloc_SL(space); ∥分配结点 scanf(space[i].data); ∥输入 A 的元素值 space[r].cur=i;r=i; ∥插入到表尾 }∥for space[r].cur=0; ∥尾结点的指针为空 for( j=1; j<=n; ++j) ∥依次输入 B 的元素,若不在当前表中,则插入,否则删除 {scanf(b); p=S; k=space[S].cur; ∥k 指向集合 A 中第一个结点 while( k!=space[r].cur&&space[k].data!=b) { p=k; k=space[k].cur; } ∥当前表中查找 if (k= =space[r].cur) { ∥当前表中不存在该元素,插入在 r 所指结点之后,且 r 的位置不变 i =Malloc_SL(space); space[i].data =b; space[i].cur =space[r].cur; space[r].cur =i; }∥if 2
  • 3. else{ space[p].cur =space[k].cur; ∥该元素已在表中,删除之 Free_SL(space,k); if(r==k) r=p; ∥若删除的是尾元素,则需修改尾指针 }∥else }∥for }∥difference 例:已知集合 A={1,2,5,8,9,3},B={4,2,7,3,1},画出利用静态链表计算(A-B) ∪(B-A)后的示意图。 (第一次测验题) 解: InitSpace_SL(space); 0 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 0/11 S= Malloc_SL(space); 0 1 2 3 4 5 6 7 8 9 10 2 2 3 4 5 6 7 8 9 10 0/11 S 集合 A: 0 1 2 3 4 5 6 7 8 9 10 1 2 5 8 9 3 8 2 3 4 5 6 7 0 9 10 0/11 S r 插入 4:∥当前表中不存在该元素,插入在 r 所指结点之后,且 r 的位置不变 if (k= =space[r].cur)//r=7,k=0 { i =Malloc_SL(space); // i = space[0].cur; // i=8 // if (space[0].cur) // space[0].cur = space[i].cur;//8->9 // return i; space[i].data =b; //b=4 space[i].cur =space[r].cur; //->0 space[r].cur =i; //0->8 }∥if 0 1 2 3 4 5 6 7 8 9 10 1 2 5 8 9 3 4 8->9 2 3 4 5 6 7 0->8 ->0 10 0/11 3
  • 4. 删除 2:∥该元素已在表中,删除之,且删除的不是尾元素,不需修改尾指针 { //p=2,=3 space[p].cur =space[k].cur; ∥space[2].cur=space[3].cur=4 Free_SL(space,k); // space[k].cur = space[0].cur; //4->9 // space[0].cur = k; //9->3 if(r==k) r=p; ∥若删除的是尾元素,则需修改尾指针 }∥else 0 1 2 3 4 5 6 7 8 9 10 1 2 5 8 9 3 4 9->3 2 3->4 4->9 5 6 7 8 0 10 0/11 插入 7://当前表中不存在该元素,插入在 r 所指结点之后,且 r 的位置不变 if (k= =space[r].cur)//r=7,得到 k=8 { i =Malloc_SL(space); // i = space[0].cur; // i=3 // if (space[0].cur) // space[0].cur = space[i].cur;//3->9 // return i; //i=3 space[i].data =b;//b=7 space[i].cur =space[r].cur;//9->8 space[r].cur =i;//8->3 }∥if 0 1 2 3 4 5 6 7 8 9 10 1 7 5 8 9 3 4 3->9 2 4 9->8 5 6 7 8->3 0 10 0/11 删除 3:∥该元素已在表中,删除之,且删除的是尾元素,需修改尾指针 { //p=6,k=7 space[p].cur =space[k].cur; ∥space[6].cur=space[7].cur=3 Free_SL(space,k); // space[k].cur = space[0].cur; //3->9 // space[0].cur = k; 9->7 if(r==k) r=p; ∥删除的是尾元素,修改尾指针,r->6 }∥else 0 1 2 3 4 5 6 7 8 9 10 1 7 5 8 9 4 9->7 2 4 8 5 6 3 3->9 0 10 0/11 r 删除 1:∥该元素已在表中,删除之,且删除的不是尾元素,不需修改尾指针 4
  • 5. { //p=1,k=2 space[p].cur =space[k].cur; ∥space[1].cur=space[2].cur=4 Free_SL(space,k); // space[k].cur = space[0].cur; // space[0].cur = k; if(r==k) r=p; ∥若删除的是尾元素,则需修改尾指针 }∥else 0 1 2 3 4 5 6 7 8 9 10 7 5 8 9 4 7->2 4 4->7 8 5 6 3 9 0 10 0/11 r 最终结果: 0 1 2 3 4 5 6 7 8 9 10 7 5 8 9 4 2 4 7 8 5 6 3 9 0 10 0/11 附:内存动态申请 怎么去理解这个内存分配和释放过程呢?先看下面这段对话: 万岁爷:爱卿,你为朕立下了汗马功劳,想要何赏赐啊? 某功臣:万岁,黄金白银,臣视之如粪土。臣年岁已老,欲告老还乡。臣乞良田千亩 以荫后世,别无他求。 万岁爷:爱卿,你劳苦功高,却仅要如此小赏,朕今天就如你所愿。户部刘侍郎,查 看湖广一带是否还有千亩上等良田未曾封赏。 刘侍郎:长沙尚有五万余亩上等良田未曾封赏。 万岁爷:在长沙拨良田千亩封赏爱卿。爱卿,良田千亩,你欲何用啊? 某功臣:谢万岁。长沙一带,适合种水稻,臣想用来种水稻。种水稻需要把田分为一 亩一块,方便耕种。 。。。。 不要莫名其妙,其实上面这段小小的对话,就是malloc 的使用过程。malloc 是一个函 数,专门用来从堆上分配内存。使用malloc 函数需要几个要求: 内存分配给谁?这里是把良田分配给某功臣。 分配多大内存?这里是分配一千亩。 是否还有足够内存分配?这里是还有足够良田分配。 内存的将用来存储什么格式的数据,即内存用来做什么?这里是用来种水稻,需要把田 5
  • 6. 分成一亩一块。 分配好的内存在哪里?这里是在长沙。 如果这五点都确定,那内存就能分配。下面先看malloc 函数的原型: (void *)malloc(int size) malloc 函数的返回值是一个void 类型的指针,参数为int 类型数据,即申请分配的内存 大小,单位是byte。内存分配成功之后,malloc 函数返回这块内存的首地址。你需要一个 指 针来接收这个地址。但是由于函数的返回值是void *类型的,所以必须强制转换成你所接收 的类型。也就是说,这块内存将要用来存储什么类型的数据。比如: char *p = (char *)malloc(100); 在堆上分配了100 个字节内存,返回这块内存的首地址,把地址强制转换成char *类型后赋 给char *类型的指针变量p。同时告诉我们这块内存将用来存储char 类型的数据。也就是说 你只能通过指针变量p 来操作这块内存。这块内存本身并没有名字,对它的访问是匿名访 问。 上面就是使用malloc 函数成功分配一块内存的过程。但是,每次你都能分配成功吗? 不一定。上面的对话,皇帝让户部侍郎查询是否还有足够的良田未被分配出去。使用malloc 函数同样要注意这点:如果所申请的内存块大于目前堆上剩余内存块(整块),则内存分配 会失败,函数返回NULL。注意这里说的“堆上剩余内存块”不是所有剩余内存块之和,因 为malloc 函数申请的是连续的一块内存。 既然malloc 函数申请内存有不成功的可能,那我们在使用指向这块内存的指针时,必 须用 if(NULL != p)语句来验证内存确实分配成功了。 既然有分配,那就必须有释放。不然的话,有限的内存总会用光,而没有释放的内存 却在空闲。与malloc 对应的就是free 函数了。free 函数只有一个参数,就是所要释放的 内 存块的首地址。比如上例: free(p); free 函数看上去挺狠的,但它到底作了什么呢?其实它就做了一件事:斩断指针变量与 这块内存的关系。比如上面的例子,我们可以说malloc 函数分配的内存块是属于p 的,因 为我们对这块内存的访问都需要通过p 来进行。free 函数就是把这块内存和p 之间的所有 关系斩断。从此p 和那块内存之间再无瓜葛。至于指针变量p 本身保存的地址并没有改变, 但是它对这个地址处的那块内存却已经没有所有权了。那块被释放的内存里面保存的值也 没有改变,只是再也没有办法使用了。 --摘自 陈正冲《C 语言深度剖析》 6