• 单链表的实现


      我们知道,数组式计算机根据事先定义好的数组类型与长度自动为其分配一连续的存储单元,相同数组的位置和距离都是固定的,也就是说,任何一个数组元素的地址都可一个简单的公式计算出来,因此这种结构可以有效的对数组元素进行随机访问。但若对数组元素进行插入和删除操作,则会引起大量数据的移动,从而使简单的数据处理变得非常复杂,低效

      为了能有效地解决这些问题,一种称为“链表”的数据结构得到了广泛应用。

    一、链表

      1、概述

      链表是一种动态数据结构,他的特点是用一组任意的存储单元(可以是连续的,也可以是不连续的)存放数据元素
      链表中每一个元素成为“结点”,每一个结点都是由数据域和指针域组成的,每个结点中的指针域指向下一个结点。Head是“头指针”,表示链表的开始,用来指向第一个结点,而最后一个指针的指针域为NULL(空地址),表示链表的结束。
      可以看出链表结构必须利用指针才能实现,即一个结点中必须包含一个指针变量,用来存放下一个结点的地址。
    实际上,链表中的每个结点可以用若干个数据和若干个指针。结点中只有一个指针的链表称为单链表,这是最简单的链表结构
    再c++中实现一个单链表结构比较简单。例如,可定义单链表结构的最简单形式如下:

    1 struct Node{
    2 
    3     int Data;
    4     Node* next;
    5 };

      这里用到了结构体类型。其中,*next是指针域,用来指向该结点的下一个结点;Data是一个整形变量,用来存放结点中的数据。当然,Data可以是任何数据类型,包括结构体类型或类类型。
      在此基础上,我们在定义一个链表类CList,其中包含链表结点的插入,删除,输出等功能的成员函数。

     1 //链表类
     2 class CList{
     3     Node* head;
     4 public:
     5     CList(){ head = NULL; }
     6     void insertList(int aData, int bData);//链表结点的插入:在结点a之前插入结点b
     7     void deleteList(int aData);//链表结点的删除
     8     void outputList();//链表结点的输出
     9     Node* getHead(){ return head; }    //获取头结点
    10 
    11 };

      2、链表结点的访问

      由于链表中的各个结点是由指针链接在一起的,其存储单元未必是连续的,因此,对其中任意结点的地址无法向数组一样,用一个简单的公式计算出来,进行随机访问。只能从链表的头指针(即head)开始,用一个指针p先指向第一个结点,然后根据结点p找到下一个结点。以此类推,直至找到所要访问的结点或到最后一个结点(指针为空)为止

      3. 链表结点的插入

      如果要在链表中的结点a之前插入结点b,则需要考虑下面几点情况。
      (1) 插入前链表是一个空表,这时插入新结点b后。
      (2) 若a是链表的第一个结点,则插入后,结点b为第一个结点。
      (3) 若链表中存在a,且不是第一个结点,则首先要找出a的上一个结点a_k,然后使a_k的指针域指向b,在令b的指针域指向a,即可完成插入。
      (4) 如链表中不存在a,则插在最后。先找到链表的最后一个结点a_n,然后使a_n的指针域指向结点b,而b指针的指针为空。

      4. 链表结点的删除

      如果要在链表中删除结点a并释放被删除的结点所占的存储空间,则需要考虑下列几种情况。
      (1) 若要删除的结点a是第一个结点,则把head指向a的下一个结点。
      (2) 若要删除的结点a存在于链表中,但不是第一个结点,则应使a得上一个结点a_k-1的指针域指向a的下一个结点a_k+1。
      (3) 空表或要删除的结点a不存在,则不做任何改变。

    二、代码

      1 #include <iostream>
      2 using namespace std;
      3 struct Node{
      4 
      5     int Data;
      6     Node* next;
      7 };
      8 
      9 //链表类
     10 class CList{
     11     Node* head;
     12 public:
     13     CList(){ head = NULL; }
     14     void insertList(int aData, int bData);//链表结点的插入:在结点a之前插入结点b
     15     void deleteList(int aData);//链表结点的删除
     16     void outputList();//链表结点的输出
     17     Node* getHead(){ return head; }    //获取头结点
     18 
     19 };
     20 
     21 /*
     22 注意:
     23 由于链表中的各个结点是由指针链接在一起的,其存储单元文笔是连续的,
     24 因此,对其中任意结点的地址无法向数组一样,用一个简单的公式计算出来,
     25 进行随机访问。只能从链表的头指针(即head)开始,
     26 用一个指针p先指向第一个结点,然后根据结点p找到下一个结点。
     27 以此类推,直至找到所要访问的结点或到最后一个结点(指针为空)为止
     28 */
     29 
     30 /*
     31 函数:void CList::insertList(int aData, int bData)
     32 功能:在链表中的结点a之前出入结点b;
     33 注意事项:
     34 如果要在链表中的结点a之前插入结点b,则需要考虑下面几点情况。
     35 (1) 插入前链表是一个空表,这时插入新结点b后。
     36 (2) 若a是链表的第一个结点,则插入后,结点b为第一个结点。
     37 (3) 若链表中存在a,且不是第一个结点,则首先要找出a的上一个结点a_k,然后使a_k的指针域指向b,在令b的指针域指向a,即可完成插入。
     38 (4) 如链表中不存在a,则插在最后。先找到链表的最后一个结点a_n,然后使a_n的指针域指向结点b,而b指针的指针为空。
     39 */
     40 void CList::insertList(int aData, int bData)
     41 {
     42     Node *p, *q, *s;        //p指向结点a,q指向结点a的上一个结点,s指向结点b
     43     s = (Node*)new(Node);    //动态分配一个新结点
     44     s->Data = bData;//设b为此结点
     45     p = head;
     46     q = NULL;//初始化指针变量
     47     if (head == NULL)    //若是空表,使b作为第一个结点
     48     {
     49         head = s;
     50         s->next = NULL;
     51     }
     52     else if (p->Data == aData)//若a是第一个结点
     53     {
     54         s->next = p;    //使结点b的next指针指向a
     55         head = s;        //头指针变为结点b
     56     }
     57     else
     58     {
     59         while (p->Data != aData && p->next != NULL)//查找结点a
     60         {
     61             q = p;
     62             p = p->next;
     63         }
     64         if (p->Data == aData)        //若有结点a
     65         {
     66             q->next = s;            //让a的上一个结点的next指针首先指向结点b
     67             s->next = p;            //然后结点b的next指针再指向结点a
     68         }
     69         else                        //若链表中不存在a,则插在最后
     70         {
     71             p->next = s;//找到链表的最后一个结点,使其next指向结点b,
     72             s->next = NULL;//而结点b的next指针为空
     73         }
     74     }
     75 }
     76 
     77 /*
     78 函数:
     79 功能:删除结点a并释放被删除的结点所占的存储空间
     80 注意事项:
     81 如果要在链表中删除结点a并释放被删除的结点所占的存储空间,则需要考虑下列几种情况。
     82 (1) 若要删除的结点a是第一个结点,则把head指向a的下一个结点。
     83 (2) 若要删除的结点a存在于链表中,但不是第一个结点,则应使a得上一个结点a_k-1的指针域指向a的下一个结点a_k+1。
     84 (3) 空表或要删除的结点a不存在,则不做任何改变。
     85 */
     86 void CList::deleteList(int aData)    //设aData是要删除的结点a中的数据成员
     87 {
     88     Node*p, *q;//p用于指向结点a,q用于指向结点a的前一个结点
     89     p = head;
     90     q = NULL;//初始化指针变量
     91     if (p == NULL)    //若是空表
     92         return;
     93     if (p->Data == aData)//若a是第一个结点
     94     {
     95         head = p->next;
     96         delete p;
     97     }
     98     else
     99     {
    100         while (p->Data != aData && p->next != NULL)    //查找结点a
    101         {
    102             q = p;
    103             p = p->next;
    104         }
    105         if (p->Data == aData)//若有结点a
    106         {
    107             q->next = p->next;
    108             delete p;
    109         }
    110     }
    111 }
    112 void CList::outputList()
    113 {
    114     Node* current = head;
    115     while (current != NULL)//不为零的时候就继续输出,并指向下一个指针
    116     {
    117         cout << current->Data << " ";
    118         current = current->next;
    119     }
    120     cout << endl;
    121 }
    122 int main()
    123 {
    124     CList A, B;
    125     int Data[10] = { 25, 41, 16, 98, 5, 67, 9, 55, 1, 121 };
    126     A.insertList(0, Data[0]); //建立链表A首结点
    127     for (int i = 1; i<10; i++)
    128         A.insertList(0, Data[i]); //顺序向后插入
    129     cout << "
    链表A:" << endl;
    130     A.outputList();
    131     A.deleteList(Data[7]);
    132     cout << "删除元素Data[7]后:" << endl;
    133     A.outputList();
    134     B.insertList(0, Data[0]); //建立链表B首结点
    135     for (int i = 0; i<10; i++)
    136         B.insertList(B.getHead()->Data, Data[i]); //在首结点处顺序向后插入
    137     cout << "
    链表B:" << endl;
    138     B.outputList();
    139     B.deleteList(67);
    140     cout << "删除元素67后:" << endl;
    141     B.outputList();
    142     
    143     return 0;
    144 }

      

      

  • 相关阅读:
    Mysql8 连接提示 Client does not support authentication protocol requested by server; consider upgrading MySQL client 解决方法
    CMSampleBufferRef解析
    AVCaptureInput和AVCaptureOutput子类介绍
    六大设计原则
    UIView绘制原理,异步绘制
    使用Pods中使用Swift和Objective-C混编-编译不通过的原因
    SVN版本控制说明与相关指令
    KVO
    KVC
    Java从0到1的成长之路
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/5887615.html
Copyright © 2020-2023  润新知