顺序表的概念和运算
- 什么是线性表
线性表是由n个元素(结点)组成的有限序列。n为线性表的长度,n=0时称为空表。
- 线性表的逻辑特征
(1)对于非空的线性表,有且有一个开始结点,它没有直接前驱,而仅有一个直接后继。
(2)对于非空的线性表,有且有一个终端结点,它没有直接后继,而仅有一个直接前驱。
(3)对于非空的线性表,内部结点(除去开始结点和终端结点)都有且仅有一个直接前驱和一个直接后继。
- 图示
- 什么是顺序表
把线性表的结点按逻辑次序依次存放在一组地址连续的存储单元里,这种方法存储的线性表简称为顺序表。例如一维数组就是采用顺序存储表示的。
- 顺序表的描述
typedef int datatype;//该用法有疑惑请看脚注
#define M 100
typedef struct
{
datatype data[M];
int last;
}sequenlist;
sequenlist L;
我们将与顺序表有关的信息封装在一起,而将顺序表类型sequenlist定义为一个结构体,这样定义使得对某一顺序表L(L是sequenlist类型的指针变量)的引用仅涉及结构变量*L,它符合程序设计的思想。
- 顺序表上的基本运算
数据的插入:对于顺序表上的数据插入,除了在表的末尾插入之外,在其他地方插入需要移动插入结点及其后的所有结点,该步骤完成以后才能进行数据插入操作,同时表的长度(last)也需要随之发生改变(增加),如下图所示:
代码实现:
//移动元素位置(i为数据x将要插入的位置)
for (int j = L.last; j >= i - 1; j--)
{
L.data[j + 1] = L.data[j];
}
//插入数据(x为插入数据)
L.data[i - 1] = x;
//表的最后一个元素的指向增加(当前表中实际存放元素数量)
L.last++;
数据的删除:对于顺序表上数据的删除,其思想与插入相反。首先选定需要删除的数据(位置),然后,移动删除数据之后的元素,均向前移动一位。事实上,删除数据,并不是真正意义上的删除,而只是数据覆盖而已,表现上为数据的删除,同时表的长度(last)也需要随之发生改变(减小),如下图所示:
代码实现:
//移动元素位置(i为删除数据的位置)
for (j = i; j <= L.last; j++)
{
L.data[j - 1] = L.data[j];
}
//表的最后一个元素的指向减小(当前表中实际存放元素数量)
L.last--;
表的长度:顺序表使用一维数组来存储,其长度为该数组实际存储数据元素个数。即为last指向的数组下标值(也是last的值),所以表的长度为last。
表的置空:顺序表的置空,是直接将last指向的值赋值为-1,当新的数据进入,又会从数组0索引处开始覆盖之前的数据,由于存在last指向,之前的数据不会对后续表中数据产生影响;而不应使用移除数据的方法实现表的置空。
至此,顺序表上的关键操作(插入、删除)叙述完毕。
程序运行结果图:
以下为完整代码:
#include"stdio.h"
#include"stdlib.h"
typedef int datatype;//该用法有疑惑请看脚注
#define M 100
#define N 10
typedef struct
{
datatype data[M];
int last;
}sequenlist;
sequenlist L;//静态
/*
sequenlist * Create_sequenlist()
{
sequenlist *p;
p= (sequenlist*)malloc(sizeof(sequenlist));
p->last = -1;
return p;
}//动态
*/
void shuru()
{
for (int i = 0; i
{
L.data[i] = rand() % 101;
L.last = i;
}
printf("\n\t\t数据已产生!\n");
}
void shuchu()
{
int i;
if (L.last != -1)
{
printf("\n\t\t顺序表中的内容为\n\t");
for (i = 0; i <= L.last; i++)//
{
printf("\t%d", L.data[i]);
}
}
else
{
printf("\n\t\t顺序表为空!\n");
}
}
void zhikong()
{
L.last = -1;
printf("\n\t\t已清空!\n");
}
void changdu()
{
if (L.last != -1)
{
printf("顺序表的长度为:\n\t\t%d\n", L.last + 1);
}
else
{
printf("\n\t\t顺序表为空!\n");
}
}
void charu()
{
if (L.last != -1)
{
int i = 0;
int x = 0;
if (L.last >= M)
{
printf("溢出!");
}
else
{
shuchu();
printf("\n你想要在第几个数据处插入?\n");
scanf_s("%d", &i);
if ((i < 0) || (i > L.last + 1))
{
printf("出现错误!");
}
else
{
printf("输入待插入的数据\n");
scanf_s("%d", &x);
//移动元素位置(i为数据x将要插入的位置)
for (int j = L.last; j >= i - 1; j--)
{
L.data[j + 1] = L.data[j];
}
//插入数据(x为插入数据)
L.data[i - 1] = x;
//表的最后一个元素的指向增加(当前表中实际存放元素数量)
L.last++;
shuchu();
}
}
}
else
{
printf("\n\t\t顺序表为空!\n");
}
}
void shanchu()
{
if (L.last != -1)
{
int i = 0, j = 0;
shuchu();
printf("\n你想要删除第几个数据?\n");
scanf_s("%d", &i);
if ((i<0) || (i>L.last + 1))
{
printf("出现错误!");
}
else
{
//移动元素位置(i为删除数据的位置)
for (j = i; j <= L.last; j++)
{
L.data[j - 1] = L.data[j];
}
//表的最后一个元素的指向减小(当前表中实际存放元素数量)
L.last--;
shuchu();
}
}
else
{
printf("\n\t\t顺序表为空!\n");
}
}
void main()
{
int b = 1, k;
L.last = -1;
while (b)
{
system("cls");
printf("\n\n\t\t顺序表上的基本运算\n\n");
printf("\t\t ----------------------------\n");
printf("\t\t|1.... 顺序表数据输入 |\n");
printf("\t\t|2.... 顺序表数据输出 |\n");
printf("\t\t|3.... 顺序表数据置空 |\n");
printf("\t\t|4.... 顺序表数据长度 |\n");
printf("\t\t|5.... 顺序表数据插入 |\n");
printf("\t\t|6.... 顺序表数据删除 |\n");
printf("\t\t|0.... 退出 |\n");
printf("\t\t ----------------------------\n");
printf("\t\t请选择:");
scanf_s("%d", &k);
switch (k)
{
case 1: shuru(); break;
case 2: shuchu(); break;
case 3: zhikong(); break;
case 4: changdu(); break;
case 5: charu(); break;
case 6: shanchu(); break;
case 0: b = 0; break;
default:printf("\n\t\t请输入正确的选择!\n");
}
if (b != 0) { printf("\n\t\t"); system("pause"); }
}
printf("\n\t\t谢谢使用!qwq\n\n\t\t");
}
如有错误,欢迎指正! _
参考文献:
数据结构:用C语言描述/唐策善等编著.-北京:高等教育出版社,1995(2011重印)
注意:typedef用法类似宏定义,意思和define相同,只是写法不同。typedef int datatype的作用在于在程序设计中,为了使一些复杂类型等更容易被理解、记忆,加速开发,而使用的一种技术。这相当于给一些类型一个别称,起到的作用都是相同的,此处就相当于给int类型起了一个别称叫datatype。1 ↩︎