线性表是最常用且最简单的一种数据结构。一个线性表是n个数据元素的有限序列,序列中的每个数据元素,可以是一个数字,可以是一个字符,也可以是复杂的结构体或对象。例如:1,2,3,4,5是一个线性表,A,B,C,D...Z是一个线性表,一列列车的车厢1,车厢2...车厢n是一个线性表。

线性表的机内表示法(又称存储结构)有2种,一种是顺序存储结构,另一种是链式存储结构。

顺序存储结构,顾名思义就是按顺序来存储的一种存储结构,比如线性表(1,2,3,4,5),共计5个元素,
每个int型的数据元素假设占用4个存储单元,假设第1个元素数字1的存储地址是1000,则第2个元素数字2的存储地址是1004,第3个元素数字3的存储地址是1008,依此类推,第n个数据元素的存储地址是LOC(an) = LOC(a1)+(n-1)k.(k表示每个数据元素占用的存储单元的长度)
显而易见,这种存储结构,相邻元素在物理位置上也相邻。
通常,我们把采用这种存储结构的线性表称为“顺序表”。

链式存储结构,它不要求相邻的元素在物理位置上也相邻,所以它可用一组处在任意位置的存储单元来存储线性表的数据元素。既然这样,那应该怎样表示数据元素之间的逻辑关系呢?
为了表示数据元素之间的逻辑关系,对于数据元素a1来说,除了存储其自身的信息之外,还需要存储一个指示其直接后继的信息,所以我们引入指针的概念:称存储数据元素信息的域称为数据域,而存储直接后继地址信息的域称为指针域。
我们形象地称这种即包含自身数据信息,又包含其直接后继地址信息的数据元素为“结点”。
显而易见,这种存储结构,相邻元素在物理位置上不一定相邻,他们之间用指针来表示逻辑关系。
通常,我们把采用这种存储结构的线性表称为“线性链表”。

有了基本的概念之后,我们就可以使用编程语言进行描述,使用C、C++、C#、Java等都可以,这篇文章我使用C语言描述。

一、顺序表

为了描述顺序表,我们首先要声明一个结构,如下:

#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量(当存储空间不够时要用到)
typedef int ElemType; //数据元素的类型,假设是int型的
typedef struct{
ElemType *elem; //存储空间的基地址
int length; //当前线性表的长度
int listsize; //当前分配的存储容量
}SqList;

定义好线性表后,就可以对它进行操作了,常见的线性表的基本操作有:创建线性表、查找元素、插入元素、删除元素、清空、归并等。

线性表的基本操作在顺序表中的实现:
1.创建线性表

int InitList(SqList &L)
{
L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));//开辟一个存储空间,并把这块存储空间的基地址赋值给elem
if (!L.elem)
{
return -1; //空间分配失败
} L.length = 0; //当前长度
L.listsize = LIST_INIT_SIZE; //当前分配量
return 0;
}

2.查找元素(按值查找)
线性表的按值查找是指在线性表中查找与给定值x相等的数据元素。完成该操作最简单的方法是从第一个元素a1开始依次和x比较,若相等,则返回该元素的下标。
若查遍整个表都没有找到与x相等的元素,则返回-1。
时间复杂度:算法的基本操作(比较x与L中第i<1,n>个元素)与元素x在表中的位置有关,也与表长有关。当a1=x时,比较1次成功,当an=x时,比较n次成功,平均比较次数为n+1/2,时间复杂度为O(n)。

int LocateElem(SqList L, ElemType x)
{
int pos = -1;
for (int i = 0; i < L.length; i++)
{
if (L.elem[i] == x)
{
pos = i;
}
}
return pos;
}

3.插入元素
时间复杂度O(L.length)即O(n)

int ListInsert(SqList &L, int i, ElemType e)
{
//判断插入位置的合法性
if (i<1 || i>L.length+1) return -1;
//判断存储空间是否够用
if (L.length >= L.listsize)
{
ElemType *newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT)*sizeof(ElemType));
if (!newbase) return -1;//存储空间分配失败
L.elem = newbase;//新基址
L.listsize += LISTINCREMENT;//增加存储容量
}
//插入操作
ElemType *q, *p; //定义2个指针变量
q = &(L.elem[i-1]); //q为插入位置(注意形参i是序号,序号是从从1开始的,而下标是从0开始的,因此这里转成下标后是i-1)
for (p = &(L.elem[L.length - 1]); p >= q; --p) //从ai到an-1依次后移,注意后移操作要从后往前进行
{
*(p + 1) = *p;
}
*q = e;
++L.length;//表长加1
return 0;
}

4.删除元素
时间复杂度O(L.length)即O(n)

int ListDelete(SqList &L, int i, ElemType &e)
{
//判断删除位置的合法性
if (i<1 || i>L.length) return -1;
//删除操作
ElemType *q, *p;//定义2个指针变量
p = &(L.elem[i - 1]);//p为被删除元素的位置(注意形参i是序号,序号是从从1开始的,而下标是从0开始的,因此这里转成下标后是i-1)
e = *p; //被删除的元素赋值给e(可能用不到,也可能用到,所以保存给e吧)
q = L.elem + L.length - 1;//q指向表尾最后一个元素(q是最后一个元素的地址)
for (++p; p <= q; ++p) //从p的下一个元素开始依次前移
{
*(p - 1) = *p;
} --L.length;//表长减1
return 0;
}

测试代码如下:

int main()
{
SqList list;
InitList(list); int n = 10; //添加10个数字给线性表list
for (int i = 0; i < 10; i++)
{
ListInsert(list, i+1, i+1);
}
//删除第5个
ElemType e;
ListDelete(list, 5, e);
printf("删除的元素是:%d\n", e); //在第2个位置插入一个元素-1
ListInsert(list, 2, -1); //输出线性表
for (int i = 0; i < 10; i++)
{
printf("%d ", list.elem[i]);
}
//输出结果是:1 -1 2 3 4 6 7 8 9 10 system("pause");
}

二、线性链表

为了描述线性链表,我们首先要声明一个结构,如下:

typedef struct LNode{
ElemType data; //数据域
struct LNode *next;//指针域
}LNode;

定义好线性链表后,就可以对它进行操作了,常见的线性链表的基本操作有:查找、插入、删除、清空等。
线性表的基本操作在线性链表中的实现:
1.1创建链表(头插法) 时间复杂度O(n)

LNode * CreateListHead(int n)
{
LNode *L;
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
LNode *p;//p为新结点,指向最后一个元素
for (int i = n; i > 0; --i)
{
p = (LNode *)malloc(sizeof(LNode));//为新结点开辟空间
scanf("%d",&p->data);
p->next = L->next;
L->next = p;
}
return L;
}

1.2创建链表(尾插法)

LNode * CreateListTail()
{
LNode *L;
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;//空表
LNode *s, *r = L;//r是尾指针 s是新结点
int x;
scanf("%d", &x);
int flag = 0;//结束标记
while (x != flag)
{
s = (LNode *)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;
scanf("%d", &x);
}
r->next = NULL;//最后一个元素next域指向NULL
return L;
}

2.查找元素(取第i个元素)

int GetElem(LNode L, int i, ElemType &e)
{
LNode *head,*p;//head是头指针,p为查找下标
head = &L;
p = head;//p的初值指向第1个元素
int j = 0;
while (p !=NULL && j<i)
{
p = p->next;
j++;
}
if (p == NULL || j>i) return -1; //第i个元素不存在
e = p->data;
return 0;
}

3.插入元素
在链表中插入结点,只需要修改指针。
若要在第i个结点之前插入元素,则首先需要找到第i-1个结点,然后修改第i-1个结点的指针。
时间复杂度O(n)

int ListInsert(LNode *L, int i, ElemType e)
{
LNode *p;//设p为第i-1个结点
//首先要找到第i-1个结点
int j = 0;
p = L;
while (p != NULL && j < i-1)
{
p = p->next;
j++;
}
//申请一个新结点
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e; s->next = p->next; //s的直接后继指向p原来的直接后继
p->next = s; //p的直接后继指向s return 0;
}

4.删除元素
若要删除第i个结点,则只需要修改第i-1个结点的指针指向第i+1个即可
时间复杂度O(L.length)即O(n)

int ListDelete(LNode *L, int i, ElemType &e)
{
LNode *p,*q;//设p为第i-1个结点 q标示删除位置
//首先要找到第i-1个结点
int j = 0;
p = L;//p为L的基地址
while (p != NULL && j < i-1)
{
p = p->next;
j++;
}
q = p->next;
p->next = q->next;//p的next域指向p->next->next e = q->data;
return 0;
}

测试代码如下:

int main()
{
LNode *L;
L = CreateListTail();//创建一个线性链表,输入0结束
ListInsert(L, 1, 100);//在第1个位置插入100
ElemType e;//待删除的元素
ListDelete(L, 3, e);//删除第3个元素
LNode *p;
p = L; printf("输出线性链表:\n");
while (p->next != NULL)
{
p = p->next;
printf("%d ", p->data);
} system("pause");
}

笔者初学数据结构,如有不足之处,欢迎指正。

使用C语言实现线性表的更多相关文章

  1. 纯C语言实现线性表

    #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 typedef int ElemType; typedef ...

  2. 学习使用C语言实现线性表

    线性表是最常用且最简单的一种数据结构.一个线性表是n个数据元素的有限序列,序列中的每个数据元素,可以是一个数字,可以是一个字符,也可以是复杂的结 构体或对象.例如:1,2,3,4,5是一个线性表,A, ...

  3. C语言实现线性表

    #include <stdio.h> #include <stdlib.h> //提供malloc()原型 /* 线性表需要的方法: 1. List MakeEmpty():初 ...

  4. 浅谈c语言的线性表的基本操作———基于严蔚敏的数据结构(c语言版)

    主要讲的是线性表的创建,插入及删除: 0. 线性表的建立,对于这类操作主要是利用了结构体的性质,对于定义的线性表的特性主要有三点:首先 Typedef struct { ElemType   *ele ...

  5. C语言实现线性表(链式存储方式)

    #include <stdio.h> #include <stdlib.h> //提供malloc()原型 typedef struct LNode *List; typede ...

  6. 数据结构算法C语言实现(二)---2.3线性表的链式表示和实现之单链表

    一.简述 [暂无] 二.头文件 #ifndef _2_3_part1_H_ #define _2_3_part1_H_ //2_3_part1.h /** author:zhaoyu email:zh ...

  7. 数据结构算法C语言实现(一)---2.2线性表的顺序表示和实现

    注意: 虽然是用C语言实现,但是考虑到使用了一个C++的特性----引用以简化代码,所以所有的代码均以cpp作为后缀,用g++编译(以后不做说明). g++版本: 一.简述 本节主要讲述线性表的顺序实 ...

  8. 线性表之顺序存储结构(C语言动态数组实现)

    线性表的定义:N个数据元素的有限序列 线性表从存储结构上分为:顺序存储结构(数组)和 链式存储结构(链表) 顺序存储结构:是用一段连续的内存空间存储表中的数据 L=(a1,a2,a3....an) 链 ...

  9. 数据结构-线性表的链式存储相关算法(C语言实现)

    链表的简单介绍 为什么需要线性链表 当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降. 线性链表的分类 按照链接方式: 按照实现角度: 线性链表的创建和简单 ...

随机推荐

  1. F5 源地址保持

    Virtusl Server: Web Portal 建议选择成Source_Addr(源地址保持).因为Web Portal提供WEB服务给用户访问,压力比较大,而源地址保持的方式处理速度比Cook ...

  2. Y480&Y580 刷slic2.1全自动教程

    由于之前时间赶,写得比较乱,现在我重新把我.安装UltraISO.2.插上一个U盘.3.用UltraISO打开setup98.img镜像4.在UltraISO的“启动”的下拉菜单里选择“写入硬盘镜像” ...

  3. ehcache配置:使用Spring+SpringMVC+Mybatis或者有shiro

    SSM框架的搭建就不在叙述了 本文主要是讲解在SSM基础上再加上ehcache 1:首先:pom.xml需要的jar <dependency> <groupId>org.myb ...

  4. Python算法应用实战之队列详解

    队列是一种先进先出(First-In-First-Out,FIFO)的数据结构.队列被用在很多地方,比如提交操作系统执行的一系列进程.打印任务池等,一些仿真系统用队列来模拟银行或杂货店里排队的顾客.下 ...

  5. 529. Minesweeper

    ▶ 扫雷的扩展判定.已知棋盘上所有点的情况(雷区 'M',已翻开空白区 'B',未翻开空白区 'E',数字区 '1' ~ '8'),现在给定一个点击位置(一定在空白区域),若命中雷区则将被命中的 M ...

  6. XE7 数据库独立运行需要的文件

    dbxase.dlldbxmss.dlldbxmss9.dlllibeay32.dllmidas.dllMSVCR100.DLL sqlncli10.dllssleay32.dll

  7. phpstorm 7.1 注册码

    phpstorm 7.1 注册码 EMBRACE ===== LICENSE BEGIN =====97393-12042010000004TIOFWznalqlK"vkzc2ilc8uub ...

  8. C# 之 日常问题积累

    https://www.cnblogs.com/xinaixia/p/3956349.html

  9. 如何快速选中某单元格所在的整行或整列 Excel教程

    我们可以使用快捷键的操作来快速选中B3单元格所在的整行或整列,操作方法如下,请大家参阅! 一.正规的快捷键操作 ①快速选中整行 按下键盘上的 Shift Space 即同时按下键盘上的Shift 空格 ...

  10. Go structs、slices、maps

    [Go structs.slices.maps] 1.定义时*在变量名后面,使用时*在变量名前面. 2.定义struct,type在前,struct关键字在后. 3.指针可以指定struct. 4.A ...