数据结构——顺序表(C语言)

简介: 数据结构——顺序表(C语言)

1.线性表

(1).线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表,链表,栈,队列,字符串...

(2).线性表在逻辑上是线性结构,也就是说连续的一条直线。但是在物理结构上并不是一定是连续的,线性表在物理上存储的,通常以数组和链表结构的形式存储。

2.顺序表

顺序表是用一段物理连续的存储单元依次存储数据元素的线性结构,一般情况下采用的数组存储。在数组上完成数据的增删查改。

在这里,我将给大家讲动态顺序表是怎么实现的。


(1).我先定义了一个结构体,因为顺序表是具有相同特性的数据元素的有限列表。所以我用SeqListDateType来typedef 了,这样我们如果是double 或者float这样的类型的话,我们就只用改变宏这里一处。

(2).因为是动态的,所以我就用指针,size就代表了顺序表中有多少个元素,capacity代表了是有多少的空间。


#define SeqListDateType int
typedef struct SeqList
{
  SeqListDateType* arr;
  int size;
  int capacity;
}SeqList;

顺序表的初始化:

第一个函数就是度顺序表的初始化,这里我是直接把ps->arr置位了NULL,size和capacity一开始是0。

void SeqListInit(SeqList* ps)
{
  ps->arr = NULL;
  ps->size = ps->capacity = 0;
}

顺序表的扩容:

因为我们是实现动态的顺序表,所以我们要处理一下,当size和capacity相等的时候,有2种情况,一种情况:一开始为0的时候,第二种情况:当空间不够的时候

这里,我用三目来实现了,如果是一开始我就给了4个int大小的空间,如果是第二种情况的话我就用扩二倍的思想来处理.

void SeqListCheckCapacity(SeqList* ps)
{
  if (ps->size == ps->capacity)
  {
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    SeqListDateType* tmp = (SeqListDateType*)realloc(ps->arr, newcapacity*sizeof(SeqListDateType)*2);
    if (tmp == NULL)
    {
      perror("realloc fail\n");
      exit(-1);
    }
    ps->capacity = newcapacity;
    ps->arr = tmp;
  }
}

顺序表的尾插:

一开始,我们开辟了4个int大小的空间,所以size一开始是0,然后就插入,然后size++就可以实现了,不过在我们插入的时候我们要考虑扩容的问题,如果空间满了,是要扩容的。


void SeqListPushBack(SeqList* ps, int x)
{
  assert(ps);
  SeqListCheckCapacity(ps);
  ps->arr[ps->size] = x;
  ps->size++;
  //SeqListInsert(ps, ps->size,x);
}

顺序表的头插:


思路:可以用迭代的思路走,但我们想一想,如果是从前面迭代的话,就会形成对数据的覆盖,所以要从后面迭代走。

我定义了end指向了4的位置,然后4要到后面的位置去,然后end--,这样当我们迭代完,顺序表0的位置就空了出来,直接把数据插入进去就可以了。

void SeqListPushFront(SeqList* ps,int x)
{
  assert(ps);
  SeqListCheckCapacity(ps);
  int end = ps->size - 1;
  while (end >=0)
  {
    ps->arr[end + 1] = ps->arr[end];
    end--;
  }
  ps->arr[0] = x;
  ps->size++;
  //SeqListInsert(ps,0,x);
}

顺序表的尾删:

顺序表尾删更简单,直接让size--就可以实现了。因为,我们打印的数据就是size范围内的数据,size减了过后就没有这个数据了。

void SeqListPopBack(SeqList* ps)
{
  assert(ps);
  ps->size--;
  //SeqListErqse(ps, ps->size-1);
}

顺序表的头删:


思路:先定义一个begin来指向第一个位置,我们迭代让后面的数据覆盖掉前面的数据就可以了。最后size--就实现了顺序表的头删。

 

void SeqListPopFront(SeqList* ps)
{
  assert(ps);
  int begin = 0;
  while (begin < ps->size - 1)
  {
    ps->arr[begin] = ps->arr[begin+1];
    ++begin;
  }
  ps->size--;
  //SeqListErqse(ps, 0);
}

顺序表的最后处理:

我们直接free掉动态开辟的空间就可以了,然后把size和capacity置为0.

void SeqListDestory(SeqList* ps)
{
  free(ps->arr);
  ps->arr = NULL;
  ps->size = ps->capacity = 0;
}

我们想一个问题,如果是在面试中,给了我们10分钟来实现顺序表,如果这样处理时间是不是可能不够呢??所以,我给大家带来另外2个函数,这样我们就可以复用这2个函数对顺序表的头插、尾插..就可以直接复用,大大节约了时间。话不多说,直接放码!!!

顺序表的指定位置插入:


思路:假设pos=2,我定义了end来指向最后一个元素,只需要将最后一个元素往后移动一位,然后end--,这样就迭代了起来,最终就可以把pos的位置空出来,然后在pos位置插入想要的元素。

void SeqListInsert(SeqList* ps, int pos, int x)
{
  assert(pos <= ps->size && pos>=0);
  SeqListCheckCapacity(ps);
  int end = ps->size - 1;
  while (end >= pos)
  {
    ps->arr[end+1] = ps->arr[end];
    end--;
  }
  ps->arr[pos] = x;
  ps->size++;
}

顺序表的指定位置删除:

思路:删除的话,其实也是一个覆盖的过程,将pos+1的位置覆盖掉pos的位置,然后迭代,临界位置就是size-1的时候,最后size--就实现了对指定位置的删除。

void SeqListErase(SeqList* ps, int pos)
{
  assert(pos >=0 && pos <= ps->size-1);
  int begin = pos+1;
  while (begin <= ps->size-1)
  {
    ps->arr[begin-1] = ps->arr[begin];
    begin++;
  }
  ps->size--;
}

这样,就可以用这两个元素来复用了!

尾插:尾插其实就是对顺序表最后的位置插入元素(注意,在最后一个位置插入的时候size已经++了,所以是ps->size)

SeqListInsert(ps, ps->size,x);

头插:头插就是对0的位置插入元素

SeqListInsert(ps,0,x);

尾删:尾删也是和尾插一样的,对最后的位置删除

SeqListErase(ps, ps->size-1);

头删:头删是对0的位置开始删除

SeqListErase(ps, 0);


相关文章
|
4月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
124 1
|
4月前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
87 4
|
4月前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
67 4
|
4月前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
69 4
|
4月前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
73 4
|
4月前
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
67 4
|
4月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】66-70
本书《趣学C语言和数据结构100例》精选了5个典型的数据结构问题及C语言实现,涵盖链表与数组操作,如有序集合的集合运算、有序序列表的合并、数组中两顺序表位置互换、三递增序列公共元素查找及奇偶数重排。通过详细解析与代码示例,帮助读者深入理解数据结构与算法设计的核心思想,提升编程技能。
53 4
|
4月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】51-55
本文介绍了五个关于链表操作的C语言实现案例,包括删除单链表中的重复元素、从两个有序链表中查找公共元素、判断一个链表是否为另一链表的连续子序列、判断循环双链表是否对称及合并两个循环单链表。每个案例都详细解析了算法思路与实现方法,涵盖了链表操作的多种场景,旨在帮助读者深入理解链表数据结构的应用,提升算法设计与编程能力。
59 4
|
25天前
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
2月前
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。