码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构与算法(一)

时间:2021-02-19 13:45:16      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:获取元素   表示   操作   center   函数   删除元素   组成   创建   最大   

  1. 推到大O阶(时间复杂度)方法:

    1. 用常数1取代运行时间中的所有加法常数
    2. 在修改后的运行次数函数中,只保留最高阶项
    3. 如果最高阶项存在且不是1,则去除与这个项相乘的常数
  2. 得到的最后结果就是大O阶

  3. 常见的时间复杂度

    例子 时间复杂度 术语
    520 O(1) 常数阶
    3n+4 O(n) 线性阶
    3n^2+4n+5 O(n^2) 平方阶
    3log(2)n+4 O(logn) 对数阶
    2n+3nlog(2)n+14 O(nlogn) nlogn阶
    n^3+ 2n^2 + 4n + 6 O(n^3) 立方阶
    2^n O(2^n) 指数阶
  4. 常用的时间复杂度所耗费的时间从小到大依次是:O(1) < O(logn) < (n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)

  5. 线性表(List):由零个或者多个数据元素组成的有限序列

    1. 元素之间是有顺序的
    2. 若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他元素都有且只有一个前驱和后继
    3. 线性表是有限的
  6. 抽象数据类型:

    1. ADT 线性表(List)

      1. 操作

        • InitList(*L):初始化操作,建立一个空的线性表L。
        • ListEmpty(L):判断线性表是否为空表,若线性表为空,返回true,否则返回false。
        • ClearList(*L):将线性表清空。
        • GetElem(L, i, *e):将线性表L中的第i个位置元素值返回给e。
        • LocateElem(L, e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回0表示失败。
        • ListInsert(*L, i, e):在线性表L中第i个位置插入新元素e。
        • ListDelete(*L, i, *e):删除线性表L中第i个位置元素,并用e返回其值。
        • ListLength(L):返回线性表L的元素个数
      2. 示例代码

        //并集代码
        //La表示A集合,Lb表示B集合
        void unionL(list *La, list Lb)
        {
            int La_len, Lb_len, i;
            
            ElemType e;
            La_len = ListLength(*La);
            Lb_len = ListLength(Lb);
            
            for(i = 1; i <= Lb_len; i++)
            {
                GetElem(Lb, i, &e);
                if( !LocateElem(*La, e))
                {
                    ListInsert(La, ++La_len, e);
                }
            }
        }
        
      3. 线性表的存储结构:顺序存储结构和链式存储结构

        1. 顺序存储的结构代码:

          #define MAXSIZE 20
          typedef int ElemType;
          typedef struct
          {
              ElemType data[MAXSIZE];
              int length;			//线性表当前长度
          }SqList;
          
          //顺序存储结构具有随机结构的特点,时间复杂度为O(1)
          
        2. 顺序存储结构封装需要三个属性:

          • 存储空间的起始位置,数组data,它的存储位置就是线性表存储空间的存储位置
          • 线性表的最大存储容量:数组长度MaxSize
          • 线性表的当前长度:length
          • 数组的长度初始化后一般不变,线性表的当前长度会改变
        3. 获取元素操作

          #define OK 1
          #define ERROR 0
          #define TRUE 1
          #define FALSE 0
          
          typedef int Status;
          
          //Status是函数的类型,其值时函数结果状态代码,如OK等
          //初始条件:顺序线性表L已存在,1 <= i <= ListLength(L)
          //操作结果:用e返回L中第i个数据元素的值
          
          Status GetElem(SqList L, int i, ElemType *e)
          {
              if( L.length == 0 || i < 1 || i > L.length)
              {
                  return ERROR;
              }
              *e = L.data[i-1];
              
              return OK;
          }
          
        4. 插入操作

          //插入算法的思路:
          /*************************************
          如果插入位置不合理,抛出异常;
          如果线性表长度大于等于数据长度,则抛出异常或动态增加数组容量;
          从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置;
          将要插入元素填入位置i处;
          线性表长+1。
          *************************************/
          
          Status ListInsert(SqList *L, int i, ElemType e)
          {
              int k;
              
              if( L->Length == MAXSIZE) 	//顺序线性表已经满了
              {
                  return ERROR;
              }
              if(i < 1 || i > L->length + 1)	//当i不在范围内时
              {
                  return ERROR;
              }
              if(i <= L -> length)	//若插入数据位置不在表尾
              {
                  //将要插入位置后数据元素向后移动一位
                  for (k=L->length - 1; k >= i-1; k--)
                  {
                      L -> data[k+1] = L -> data[k];
                  }
              }
              
              L -> data[i - 1] = e;	//将新元素插入
              L -> length++;
              
              return OK;
          }
          
        5. 删除操作

          /************************************
          删除算法思路:
          如果删除位置不合理,抛出异常
          取出删除元素
          从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置
          表长-1
          ************************************/
          
          Status ListDelete(SqList *L, int i, ElemType e)
          {
              int k;
              
              if( L->Length == 0) 	//顺序线性表为空表
              {
                  return ERROR;
              }
              if(i < 1 || i > L->length)	//当i不在范围内时
              {
                  return ERROR;
              }
              *e = L->data[i-1];
              
              if(i < L -> length)
              {
                  for (k=i; k < L->length; k++)
                  {
                      L -> data[k-1] = L -> data[k];
                  }
              }
              
              L -> length--;
              
              return OK;
          }
          
        6. 线性表顺序存储结构,插入和删除的时间复杂度,最好情况为O(1),最坏情况为O(n),平均情况为O(n)。适合元素个数比较稳定,不经常插入和删除元素,更多是存取数据的应用

        7. 顺序结构的优缺点

          • 优点:
            • 无须为表示表中元素之间的逻辑关系而增加额外的存储空间
            • 可以快速地存取表中任意位置的元素
          • 缺点:
            • 插入和删除操作需要移动大量元素
            • 当线性表长度变化较大时,难以确定存储空间的容量
            • 容易造成存储空间的“碎片”
      4. 单链表

        1. 单链表存储结构

          typedef struct Node
          {
              ElemType data;	//数据域
              struct Node* Next;	//指针域
          }Node;
          typedef struct Node* LinkList;
          
          //结点由存放数据元素的数据域和存放后继结点地址的指针域组成
          
        2. 单链表的读取

          /***************************************
          获得链表第i个数据的算法思路:
          声明一个结点p指向链表第一个结点,初始化j从1开始
          当j < i 时,就遍历链表,让p的指针向后移动,不断指向下一个结点, j+1
          若到链表末尾p为空,则说明第i个元素不存在
          否则查找成功,返回结点p的数据
          ****************************************/
          
          Status GetElem( LinkList L, int i, ElemType *e )
          {
              int j;
              LinkList p;
              
              p = L->next;
              j = 1;
              
              while( p && j < i)
              {
                  p = p ->next;
                  ++j;
              }
              
              if( !p || j > i)
              {
                  return ERROR;
              }
              
              *e = p->data;
              
              return OK;
          }
          
        3. 单链表的插入

          /***********************************************
          单链表第i个数据插入结点的算法思路:
          声明一结点p指向链表头结点,初始化j从1开始
          当j<1时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
          若到链表末尾p为空,则说明第i个元素不存在;
          否则查找成功,在系统中生成一个空结点s
          将数据元素e赋值给s->data
          单链表的插入刚才两个标准语句
          返回成功
          ***********************************************/
          
          Status ListInsert( LinkList *L, int i, ElemType *e )//LinkList是结构体的指针,指针做形参时都要加*表示是指针
          {
              int j;
              LinkList p, a;
              
              p = *L;
              j = 1;
              
              while( p && j < i)		//用于寻找第i个结点
              {
                  p = p ->next;
                  j++;
              }
              
              if( !p || j > i)
              {
                  return ERROR;
              }
              
              s = (LinkList)malloc(sizeof(Node));
              s->data = e;
              
              s->next = p->next;
              p->next = s;
              
              return OK;
          }
          
        4. 单链表的删除

          假设元素a2的结点为q,要实现结点q删除单链表的操作,其实就是将它的前继结点的指针绕过指向后继结点即可

          /***********************************
          单链表第i个数据删除结点的算法思路:
          声明结点p指向链表第一个结点,初始化j=1
          当j<1时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1
          若到链表末尾p为空,则说明第i个元素不存在
          否则查找成功,将欲删除结点p->next赋值给q
          单链表的删除标准语句p->next = q->next
          将q结点中的数据赋值给e,作为返回
          释放q结点
          ************************************/
          
          Status ListDelete(LinkList *L, int i, ElemType *e)
          {
              int j;
              LinkList p,q;
              
              p = *L;
              j = 1;
              
              while(p->next && j < i)
              {
                  p = p->next;
                  ++j;
              }
              
              if(!(p->next) || j > i)
              {
                  return ERROR;
              }
              
              q = p->next;
              p->next = q->next;
              
              *e = q->data;
              free(q);
              
              return OK;
          }
          
        5. 单链表的创建

          /*************************************
          声明一结点p和计数器变量i
          初始化一空链表L
          让L的头结点的指针指向NULL,即建立一个带头结点的单链表
          循环实现后继结点的赋值和插入
          **************************************/
          
          //头插法
          void CreateListHead(LinkList *L, int n)
          {
              LinkList p;
              int i;
              
              srand(time(0));			//初始化随机数种子
              
              *L = (LinkList)malloc(sizeof(Node));
              (*L)->next = NULL;
              
              for(i = 0; i < n; i++ )
              {
                  p = (LinkList)malloc(sizeof(Node));	//生成新结点
                  p->data = rand()%100 + 1;
                  p->next = (*L)->next;
                  (*L)->next = p;
              }
          }
          
          //尾插法
          void CreateListTail(LinkList *L, int n)
          {
              LinkList p, r;
              int i;
              
              srand(time(0));
              *L = (LinkList)malloc(sizeof(Node));
              r = *L;
              
              for(i = 0; i < n; i++ )
              {
                  p = (Node *)malloc(sizeof(Node));
                  p->data = rand()% 100 + 1;
                  r->next = p;
                  r = p;		
              }
              
              r->next = NULL;
          }
          
        6. 单链表整表删除

          /******************************
          声明结点p和q
          将第一个结点赋值给p,下一个结点赋值给q
          循环执行释放p和将q赋值给p的操作
          *******************************/
          
          Status ClearList(LinkList *L)
          {
              LinkList p, q;
              
              p = (*L) ->next;
              
              while(p)
              {
                  q = p->next;
                  free(p);
                  p = q;
              }
              (*L)->next = NULL;
              
              return OK;
          }
          
      5. 单链表结构与顺序存储结构优缺点:

        1. 存储分配方式:
          • 顺序存储结构用一段连续的存储单元依次存储线性表的数据元素。
          • 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素。
        2. 时间性能:
          • 查找
            • 顺序存储结构O(1)
            • 单链表O(n)
          • 插入和删除
            • 顺序存储结构需要平均移动表长一半的元素,时间为O(n)
            • 单链表在计算出某位置的指针后,插入和删除时间仅为O(1)
        3. 空间性能:
          • 顺序存储结构需要预分配存储空间,分大了容易造成空间浪费,分小了容易发生溢出
          • 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
        4. 结论:
          • 若线性表需要频繁查找,很少进行插入和删除操作是,宜采用顺序存储结构
          • 若需要频繁插入和删除时,宜采用单链表结构

数据结构与算法(一)

标签:获取元素   表示   操作   center   函数   删除元素   组成   创建   最大   

原文地址:https://www.cnblogs.com/zonkidd/p/14412203.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!