数据结构——线性表(顺序实现)

    好好学习基础知识,出人头地就靠它了,内外兼修。(好吧,我现在内外都不行)写这篇文章的目的就是为了,巩固刚学完的线性表,个人能力有限,若有不当之处,望指出。

线性表

  好了,扯完了,说正事:

  1、定义

    线性表是一种及其常用的并且最简单的一种数据结构。简单来说,线性表就是集合里的元素的有限排列。(在这里我把集合定义为具有相同属性的元素,会有些狭义)

  在线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储),但是把最后一个数据元素的尾指针指向了首位结点)[百度百科]

  怎么说呢,毕竟数据结构毕竟是逻辑结构,逻辑上符合线性结构的特征即可,存储结构能实现就行。线性表的很重要!很重要!很重要!后面的栈,队列,串等都是基于线性表的基础上实现的,所以说一定要学好线性表

  2、线性表的特点:

    对于任意的的非空线性表或者线性结构有:

      1、存在唯一一个被称为 ”第一个“的元素

      2、存在唯一一个被称为 ”最后一个“的元素

      3、出第一个元素之外,每一个元素都存在一个后继

      4、除最后一个元素之外,每一个元素都存在一个前驱

  3、基本操作

    1、Create(*L)创建空表

    2、InitEmpty(*L)初始化

    3、getLength(*L)获取长度

    4、Insert(*L)插入元素

    5、Remove(*L)移除元素

    6、IsEmpty(*L)空表检测

    7、IsFulled(*L)表满检测(顺序表常用,链式表基本不用)

    8、Delete(*L)删除表

    9、getElemt(*L)获取元素

    10、Traverse(*L)遍历输出所有元素

    11、Clear(*L)清除所有元素

  4 、实现

    好了最麻烦的事情开始了,数据结构在计算机上的的映射。众所周知,线性表有两种实现方法,一种是顺序表,另一种是链式表,这两种结构实现最大的不同在于前者逻辑关系无需存储空间,而后者则需要用额外的空间(顺便记录一下,指针大小只由环境有关(严格意义上说和CPU的位数有关)本篇只实现顺序结构)。

    1、顺序表:

      先说一下概念:用一组地址连续的存储单元依次存储线性表的数据元素,这种存储结构的线性表称为顺序表。

    很明显对于顺序表来说:逻辑上相邻的数据元素,物理次序也是相邻的。

      特点:

        对表中任意元素访问时间复杂度都为常数级。

        尾部插入元素时间复杂度也为常量级。

  下面是重点!!!

    说明一下,讲解的时候实现语言为C,后续会贴上C++和Python

      实现:

   敲~~~键盘,敲~~键盘!敲~~~键盘,敲~~键盘!

  结构定义:  

 1 #define YWZLIST_INIT_SIZE 8
 2 #define INC_SIZE 3 //空间增量的大小
 3
 4 typedef int ElemType;
 5 typedef struct listnode
 6 {
 7     ElemType *base;
 8     int capacity; //顺序表容量
 9     int size;     //表的大小
10 } YWZlist;

  函数声明:

 1 bool IsEmpty(YWZlist *list);                         //空表检测
 2 bool IsFull(YWZlist *list);                          //表满检测
 3 bool Inc(YWZlist *list);                             //增加顺序表的容量
 4 void InitSeqlist(YWZlist *list);                     //初始化顺序表
 5 void Push_back(YWZlist *list, ElemType x);           //在顺序表的末尾插入元素
 6 void Push_front(YWZlist *list, ElemType x);          //在顺序表的头部插入元素
 7 void Show_list(YWZlist *list);                       //显示顺序表中的元素
 8 void Pop_back(YWZlist *list);                        //删除顺序表最后一个元素
 9 void Pop_front(YWZlist *list);                       //删除顺序表第一个元素
10 void Insert_pos(YWZlist *list, int pos, ElemType x); //在顺序表的选定位置上插入数据
11 int Find(YWZlist *list, ElemType key);               //在顺序表中查找元素key的下标
12 int Length(YWZlist *list);                           //求顺序表的长度
13 void Delete_pos(YWZlist *list, int pos);             //删除顺序表中特定位置的数据元素
14 void Delete_val(YWZlist *list, int key);             //删除顺序表中值为key的数据元素
15 void Sort(YWZlist *list);                            //冒泡排序
16 void Reverse(YWZlist *list);                         //逆置顺序列表
17 void Clear(YWZlist *list);                           //清除顺序表中的所有元素
18 void Destroy(YWZlist *list);                         //摧毁顺序表
19 void Merge(YWZlist *lt, YWZlist *la, YWZlist *lb);   //合并两个顺序列表

    上面一共19个函数,空表和表满函数就不写了

  1、初始化:

    思路很明确,先开辟一个最小的数组空间,给capacity赋值

void InitYWZlist(YWZlist *list) //初始化顺序表
{
    //开辟初始空间,开辟失败返回空
    list->base = (ElemType *)malloc(sizeof(ElemType) * YWZLIST_INIT_SIZE);

    if (list->base == NULL)
    {
        printf("内存不足!\n");
        return;
    }

    list->capacity = YWZLIST_INIT_SIZE - 1;
    list->size = -1;
}

初始化顺序表

  2、扩容:

    顺序表扩容不比链表,顺序表需要重新开劈空间需要用到realloc函数,来看一下函数原型

    _CRTIMP void* __cdecl __MINGW_NOTHROW	realloc	(void*, size_t);  //传进去的是要改变大小的指针

    嗯,两个参数,一个指针,一个大小,由于要新开辟一块空间,所以我们不能用原指针来指向新开辟的空间,我i们需要一个新的之指针,下一步当然是计算需要多少空间,这就和malloc函数一样了,自己琢磨琢磨,记得改变capacity的值,贴代码:

bool Inc(YWZlist *list)
{
    //重新分配内存空间
    ElemType *newspace = (ElemType *)realloc(list, sizeof(ElemType) * (list->capacity + INC_SIZE));
    if (newspace == NULL)
    {
        printf("内存空间已满,无法再分配内存空间!\n");
        return false;
    }

    list->base = newspace;
    list->capacity += INC_SIZE;

    return true;
}

扩容

   3、尾部插入:

     顺序表的尾部插入无比的简单,因为物理上相邻,所以访问最后一个元素的时间复杂度为常量级。插入元素我们不仅需要考虑表是否表满,同时我们还需要检测是否可以开辟新的空间。只有当表满且内存不足才能返回异常。

void Push_back(YWZlist *list, ElemType x)
{
    //当表满且无法扩容
    if (IsFull(list) && !Inc(list))
    {
        printf("顺序表容量已满,无法再在表尾继续插入新元素!\n");
        return;
    }

    list->base[list->size] = x;
    list->size++;
}

尾部插入

  4、头部插入

     这个就麻烦了,因为物理相邻,所以我们得把所有元素都向后移。(这也是链式表出现的原因之一)当然啦,打印错误的条件和尾部插入相同。

void Push_front(YWZlist *list, ElemType x)
{
  if (IsFull(list) && !Inc(list))
  {
    printf("顺序表容量已满,无法再在表尾继续插入新元素!\n");
    return;
  }

  for (int i = list->size; i > 0; i--)
  {
    list->base[i] = list->base[i - 1];
  }
  list->base[0] = x;
  list->size++;
}

头部插入

  5、第i个索引插入

    说完尾部和头部,我们来类推一下第i个元素删除的。

    第一步,都不用想肯定是先找到第i个元素,

    第二步,将n-i+1个元素个元素向后移动,

    第三步,插入元素

    第四步,size++

  按着这个思路贴上代码

void Insert_pos(YWZlist *list, int pos, ElemType x)
{
  if (pos < 0 || pos > list->size)
  {
    printf("插入位置不合法,无法插入元素!\n");
    return;
  }
  if (list->size >= list->capacity && !Inc(list))
  {
    printf("顺序表容量已满,无法在插入新的元素!\n");
    return;
  }
  for (int i = list->size; i > pos; i--)
  {
    list->base[i] = list->base[i - 1];
  }
  list->base[pos] = x;
  list->size++;
}

任意位置插入

  6、遍历

    这个直接贴代码,太简单了,不做作说明

void Show_list(YWZlist *list)
{
  for (int i = 0; i < list->size; i++)
  {
    printf("%d ", list->base[i]);
  }
  printf("\n");
}

遍历

  7、尾部删除

    删除其实没有想象中的那么难,就是把size--,因为你下次插入就是直接覆盖了,和原先的值没有任何关系。当然你得先判断一下表是否为空

void Pop_back(YWZlist *list)
{
  if (list->size == 0)
  {
    printf("顺序表已空,无法再在表尾删除元素!\n");
    return;
  }
  list->size--;
}

尾部删除

  8、头部删除

    个人觉得无论是链表还是顺序表,只要会了插入,删除类推一下就会了。打个比方顺序表的头部插入是,一个个往后推,那么删除就是一个个往前移。当然一个是判断表满一个是判断表空

void Pop_front(YWZlist *list)
{
  if (list->size == 0)
  {
    printf("顺序表已空,无法再在表头删除元素!\n");
    return;
  }
  for (int i = 0; i < list->size - 1; i++)
  {
    list->base[i] = list->base[i + 1];
  }
  list->size--;
}

头部删除

  9、指定位置删除

    类推吧,

    第一步,找到第i个元素

    第二部,将从第i+1到第n个元素向前移动1

    第三步,size--;

   是不是和插入很像,所以有些代码是很像的

void Delete_pos(YWZlist *list, int pos)
{
  if (pos < 0 || pos >= list->size)
  {
    printf("删除位置不合法,无法删除元素!\n");
    return;
  }
  for (int i = pos; i < list->size - 1; i++)
  {
    list->base[i] = list->base[i + 1];
  }
  list->size--;
}

删除指定位置的元素

  10、按元素删除

    这个是我觉得,一般人找东西,都只记得叫什么名字而不是第几个,所以写了一个按元素删除的。其实思路和指定位置删除一样找到最前端的一样的元素后插入即可(有bug,当表中存在重复元素的时候,只会添加到最前面那个)

void Delete_val(YWZlist *list, int key) //删除顺序表中值为key的数据元素
{
  int pos = Find(list, key);
  if (pos == -1)
  {
    printf("顺序表中没有这个元素!\n");
    return;
  }
  Delete_pos(list, pos);
}

按元素删除

  11、元素查找

    不打算说,贴代码

int Find(YWZlist *list, ElemType key) //在顺序表中查找元素key的下标
{
  for (int i = 0; i < list->size; i++)
  {
    if (list->base[i] == key)
      return i;
  }
  return -1;
}

元素查找

  12、返回长度

    size中记录了表长,直接return就好了

int Length(YWZlist *list)
{
  return list->size;
}

表长

  13、排序

    冒泡,不在这里做说明,自己去看。其实可以直接调用qsort函数的写一个compare函数就行了

void Sort(YWZlist *list)
{
  for (int i = 0; i < list->size - 1; i++)
  { //排序的趟数(例如5个数据需要比较4趟)
    for (int j = 0; j < list->size - 1 - i; j++)
    { //每一趟比较中的比较次数(例如5个数据在第0趟需要比较4次)
      if (list->base[j] > list->base[j + 1])
      {
        ElemType temp = list->base[j];
        list->base[j] = list->base[j + 1];
        list->base[j + 1] = temp;
      }
    }
  }
}

冒泡排序

  14、顺序表逆序

  要么写个for二分表只执行到n/2,要么写个while,大小指针(不是真正意义上的指针)小指针大于大指针的时候停止

void Reverse(YWZlist *list) //逆置顺序列表
{
  if (list->size == 0 || list->size == 1)
  {
    return;
  }
  int low = 0, high = list->size - 1;
  while (low < high)
  {
    ElemType temp = list->base[low];
    list->base[low] = list->base[high];
    list->base[high] = temp;
    low++;
    high--;
  }
}

顺序表逆序

  15、清空表

  无比简单,就一句size = -1;

void Clear(YWZlist *list)
{
  list->size = 0;
}

清除顺序表中的所有元素

  16、删除表

  free完毕之后,将所有成员重置

void Destroy(YWZlist *list)
{
  free(list->base);
  list->base = NULL;
  list->capacity = 0;
  list->size = 0;
}

摧毁顺序表

  17、合并两个顺序表

  这个就比较麻烦了

  第一步:开辟足够的空间

  第二步:让La与Lb比较,谁大/小存谁,直到一个表结束

  第三步:将余下的元素都,存入表Lc中。

  第四步:计算表长。

void Merge(YWZlist *lt, YWZlist *la, YWZlist *lb)
{
  lt->capacity = la->size + lb->size;
  lt->base = (ElemType *)malloc(sizeof(ElemType) * lt->capacity);
  //assert(lt->base != NULL);
  int ia = 0, ib = 0, ic = 0;
  while (ia < la->size && ib < lb->size)
  {
    if (la->base[ia] < lb->base[ib])
    {
      lt->base[ic++] = la->base[ia++];
    }
    else
    {
      lt->base[ic++] = lb->base[ib++];
    }
  }
  while (ia < la->size)
  {
    lt->base[ic++] = la->base[ia++];
  }
  while (ib < lb->size)
  {
    lt->base[ic++] = lb->base[ib++];
  }
  lt->size = la->size + lb->size;
  Show_list(lt);
}

合并两个顺序列表

  本篇只实现顺序表

原文地址:https://www.cnblogs.com/daker-code/p/11297336.html

时间: 2024-12-15 05:23:40

数据结构——线性表(顺序实现)的相关文章

java实现数据结构-线性表-顺序表,实现插入,查找,删除,合并功能

package 顺序表; import java.util.ArrayList; import java.util.Scanner; public class OrderList { /** * @param args * @author 刘雁冰 * @2015-1-31 21:00 */ /* * (以下所谓"位置"不是从0开始的数组下标表示法,而是从1开始的表示法.) * (如12,13,14,15,16数据中,位置2上的数据即是13) * * 利用JAVA实现数据结构-线性表-顺

数据结构线性表顺序结构的实现

package com.he.list; import java.util.Arrays; import org.w3c.dom.ls.LSException; class ArrayList { private int length;// the list's length private int[] store;// store the data // initialize an empty list public ArrayList initList(String name) { retu

数据结构----线性表顺序和链式结构的使用(c)

PS:在学习数据结构之前,我相信很多博友也都学习过一些语言,比如说java,c语言,c++,web等,我们之前用的一些方法大都是封装好的,就java而言,里面使用了大量的封装好的方法,一些算法也大都写好了,java还有三个特性,封装.继承.多态.当然这里不是讲Java,这里主要是说内部结构,大家都知道数据结构有些东西是分为逻辑结构和物理结构的,物理结构有分为顺序结构和链式结构,有不懂得可以百度百科,这里主要是分享线性表的顺序结构.那么什么是线性表呢,线性表是最基本.最简单.也是最常用的一种数据结

数据结构-线性表-顺序表

总括: 线性表是一种最简单的数据结构,线性表的主要操作特点是可以在任意位置插入和删除一个数据元素. 线性表可以用顺序存储结构和链式存储结构存储,用顺序存储结构实现的线性表称为顺序表,用链式存储结构实现线性表称为链表. 1,线性表概述: 线性表:线性表是一种可以在任意位置进行插入和删除数据元素操作的,有n个(n>=0)个相同类型数据元素a0,a1,. . .an组成的线性结构. 线性表抽象数据类型:抽象数据类型是指一个逻辑概念上的类型和这个类型上的操作集合:因此,线性表的抽象数据类型主要包括两个方

数据结构——线性表顺序表示(5)

题目来源于王道2018数据结构考研复习指导线性表的综合练习 编译环境:VS2015 题目:从顺序表中删除其值在给定s与t之间(包含s和t,要求s<t)的所有元素,如果s或t不合理或者顺序表为空,则显示出错信息并退出运行. 注意:这道题目与上一道有所不同.上一道题目所要求的表是有序表,而这道题则没要求,因此要考虑乱序的情况. 思路:举个例子,随意给一个顺序表的元素为{1,5,4,2,3,6},需要删除的数字区间是闭区间[2,5],计数变量j=0,记录在闭区间的数的个数 具体流程: i=0,  L.

基础数据结构-线性表-顺序表的合并操作

因为最近笔记本B面裂了准备去修,复杂些的会优先加上注释,所以在家先把代码和题目贴上来以后补文字,有疑问可以在下面留言. 顺序表的合并操作 题目描述建立顺序表的类,属性包括:数组.实际长度.最大长度(设定为1000) 已知两个递增序列,把两个序列的数据合并到顺序表中,并使得顺序表的数据递增有序输入第1行先输入n表示有n个数据,接着输入n个数据,表示第1个序列,要求数据递增互不等 第2行先输入m表示有m个数据,接着输入m个数据,表示第2个序列,要求数据递增互不等输出顺序表内容包括顺序表的实际长度和数

数据结构&gt;&gt;线性表【注意】--&gt;链表求A-B(原A与B都递增,求完的A-B不改变A原来的顺序)

/*关于链表的题目 * A.B是两个递增有序的单链表,元素个数分别是m和n,求 * 集合A-B,并将结果保存在A中,且仍然保持递增有序. * converge_ab */ #include <iostream.h> using namespace std; typedef struct lnode{ int data; struct lnode * next; }lnode; int main(){ lnode * create_chain(int num,int interval,int s

数据结构与算法 1 :基本概念,线性表顺序结构,线性表链式结构,单向循环链表

[本文谢绝转载] <大纲> 数据结构: 起源: 基本概念 数据结构指数据对象中数据元素之间的关系  逻辑结构 物理结构 数据的运算 算法概念: 概念 算法和数据结构区别 算法特性 算法效率的度量 大O表示法 时间复杂度案例 空间复杂度 时间换空间案例 1)线性表: 线性表初步认识: 线性表顺序结构案例 线性表顺序结构案例,单文件版 线性表的优缺点 企业级线性表链式存储案例:C语言实现 企业级线性表链式存储案例:C语言实现 单文件版 企业级线性表链式存储案例,我的练习  线性表链式存储优点缺点

C++数据结构与算法_2_线性表 --顺序表的应用示例

h2.western { font-family: "Liberation Sans",sans-serif; font-size: 16pt; }h2.cjk { font-family: "微软雅黑"; font-size: 16pt; }h2.ctl { font-family: "AR PL UMing CN"; font-size: 16pt; }h1 { margin-bottom: 0.21cm; }h1.western { fon

C++数据结构与算法_1_线性表 --顺序表的实现与分析

顺序表的实现与分析 引 --线性表的抽象基类: template <typename T> class LinearList { public: LinearList(); ~LinearList(); virtual int Size() const = 0; //返回线性表所能够存储的最大长度 virtual int Length() const = 0; //当前线性表的长度 virtual int Search(T &x) const = 0; virtual int Loca