一、前言
顺序表是线性表(链式表和顺序表)的一种,线性表是线性排列的一组具有相同数据类型的元素的有限集合,除第一个元素外,所有的元素都有且只有一个直接后驱。除最后一个元素外,所有的元素都有且只有一个直接前驱。它是数据结构中最常用也是最基本最简单的数据结构,它的基本操作有检索元素,插入元素,删除元素.......接下来会解析顺序表的概念和使用(含c,c++,java三种语言实现)。
二、顺序表
(1)概念:
顺序表即按顺序存储的一组有限的含有相同元素的数据集合。顺序存储指的是,集合里面的元素都是按照次序排列在一块连续的存储空间中。比如有这样的一个数据集合(a1,a2,a3.....ai,ai+1......an),表示该集合中的元素是按照a1,a2这样的顺序存储的。如果是在c语言中,知道了a1的地址,那么就可以推算出第i个元素的地址,公式如下:
addr(ai)=addr(a1)+(i-1)*d。
其中d表示一个元素占据的存储空间大小。在很多高级程序设计语言中,顺序表的最直接的表现形式就是一维数组了。大家都知道数组的元素是有一个上限的,既是容量,因此,在使用顺序表的来处理数组的时候,数组的容量要足够大,这样才不至于导致数组空间不足。接下来了解一下,顺序表可以有哪些基本操作(其实很多操作都是可以在自己理解的基础上总结出来的,这里通过基本操作来了解顺序表的使用,目的是发散思维)。
(2)基本操作:
①、顺序表的初始化
顺序表的初始化即构造一个空表,这里我们命名为init(接下里的操作都将遵循这个名字)。
②、添加元素到指定的位置
将指定元素添加到线性表指定的位置,这里命名为insert。
③、删除指定位置的元素
将指定位置的元素删除,这里命名为delete。
④、查找指定元素在表中的位置
查找指定元素的位置,这里命名为get。
三、顺序表在C语言中的实现
代码如下:
/*
c语言实现顺序表的基本操作
*/
#include<stdio.h>
#include<stdlib.h>
//最多存储100个元素
#define MAXSIZE 100//注意预定义的语法没有分号也没有=号
//定义一个线性表结构,注意strcut里面的元素是不可以初始化的
struct OrderTable
{
int element[MAXSIZE];//元素表
int last;//指示当前元素中最后一个元素的位置
};
//声明基本操作
struct OrderTable* init();//初始化
int insert(struct OrderTable *L, int x, int i);//添加一个元素到指定位置
int delete(struct OrderTable *L, int i);//将指定位置的元素删除
int get(struct OrderTable *L, int i);//获取指定位置的值
int main(void)
{
struct OrderTable *L = init();
for (int i = 1; i <=50; i++)
{
insert(L, i*2,i);
}
printf("输出列表元素:\n");
for (int i = 1; i <= 50; i++)
{
printf("%d ",get(L, i));
if (i % 10 == 0)
printf("\n");
}
delete(L, 1);
printf("输出列表元素:\n");
for (int i = 1; i <= 50; i++)
{
printf("%d ", get(L, i));
if (i % 10 == 0)
printf("\n");
}
return 0;
}
/*
初始化顺序表并返回指针对象
*/
struct OrderTable* init()
{
struct OrderTable *L;
//申请一个足以存放100个元素的存储空间并返回,malloc返回值是void *,所以需要强制转换对象
L = (struct OrderTable*)malloc(MAXSIZE*sizeof(struct OrderTable));
L->last = -1;
return L;
}
/*
将指定元素插入到表中的指定位置
*/
int insert(struct OrderTable *L, int x, int i)
{
//搞清楚的一个概念就是数组是从0开始算的,100的元素其实是a[0]-a[99]。所以第i个位置实际上是a[i-1];
if (L->last == MAXSIZE - 1)
{
printf("表中元素已满,不允许插入");
return -1;
}
if (i<0 || i>L->last + 2)
{
printf("插入的位置不允许");
return -1;
}
else
{
for (int j = L->last; j >= i - 1; j--)
{
L->element[j + 1] = L->element[j];
}
L->element[i - 1] = x;
L->last++;
return 1;
}
}
/*
删除指定位置的元素
*/
int delete(struct OrderTable *L, int i)
{
if (i<0 || i>L->last + 1)
{
printf("指定的位置不存在");
return 0;
}
else
{
for (int j = i; j <= L->last - 1; j++)
{
L->element[j - 1] = L->element[j];
}
L->last--;
return 1;
}
}
/*
获取指定位置的元素
*/
int get(struct OrderTable *L, int i)
{
if (i >= 1 && i <= L->last + 1)
{
return L->element[i - 1];
}
printf("该位置没有值");
return -1;
}
上述实现过程,最重要的是注意列表的下标是从0开始的,而我们所说的位置则是从1开始的。接下来我们分析一下个方法的时间渐进复杂度(此概念这里不普及了,因为数学表达式不好输入,读者自行补充相关知识)。
首先是
int insert(struct OrderTable *L, int x, int i)
因为i可能是任意位置,假设每个位置被插入的概率是pi,当前的数组长度是n,则pi=1/(n+1),
其次,此方法中执行次数最多的是
L->element[j + 1] = L->element[j];
总共执行了(n-i+1)+(n-i)+......+1+0次。(这里其实是一个等差级数)
所以时间渐进复杂度位((n-i+1)+....+0)*pi=n/2;即为n。
剩余的方法的时间渐进复杂度有读者自行推断。
运行结果:
四、顺序表在C++中的实现
首先定义头文件:
#include <iostream>
class OrderTable
{
public:
OrderTable();
~OrderTable();
/*
讲指定元素添加到顺序表里面
*/
int insertElement( int x, int i)
{
if (this->last == 100 - 1)
{
std::cout << "数组已满" << std::endl;
return -1;
}
if (i <= 0 || i > this->last + 2)
{
std::cout << "插入位置错误" << std::endl;
return -1;
}
else
{
int j;
for (j = this->last; j >= i - 1; j--)
{
this->element[j + 1] = this->element[j];
}
this->element[j + 1] = x;
this->last++;
return 1;
}
}
/*
删除指定位置的元素
*/
int deleteELement( int i)
{
if (i <= 0 || i >this->last + 1)
{
std::cout << "删除的位置不正确" << std::endl;
return -1;
}
else
{
for (int j = i; j < this->last; j++)
{
this->element[j - 1] = this->element[j];
}
this->last--;
return 1;
}
}
/*
获取指定位置的元素
*/
int getElement(int i)
{
if (i <= 0 || i > this->last + 1)
{
std::cout << "位置不正确" << std::endl;
return -1;
}
else
return this->element[i - 1];
}
private:
int element[100];
int last = -1;
};
OrderTable::OrderTable()
{
}
OrderTable::~OrderTable()
{
}
然后是主函数文件:
// OrderCPP.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include "Order.h"
using std::cout;
using std::endl;
int main()
{
OrderTable orderTable;
for (int i = 1; i <= 50; i++)
{
orderTable.insertElement(i * 2, i);
}
for (int i = 1; i <= 50; i++)
{
cout << orderTable.getElement(i) << " ";
if (i % 10 == 0)
cout << endl;
}
orderTable.deleteELement(1);
for (int i = 1; i <= 50; i++)
{
cout << orderTable.getElement(i) << " ";
if (i % 10 == 0)
cout << endl;
}
system("pause");
return 0;
}
其中this是每个class都隐含的指针对象,它是一个指向自己的对象。
运行结果:
五、顺序表在java中的实现
public class OrderTable {
private int element[];
private int last;
OrderTable() {
element=new int[100];
last = -1;
}
/**
* 添加元素
*
* @param x
* @param i
* @return
*/
public int insert(int x, int i) {
if (last == 100 - 1) {
return -1;
}
if (i <= 0 || i > last + 2) {
return -1;
} else {
int j;
for (j = last; j >= i - 1; j--) {
element[j + 1] = element[j];
}
element[j + 1] = x;
last++;
return 1;
}
}
/**
* 删除元素
*
* @param i
* @return
*/
public int delete(int i) {
if (i <= 0 || i > last + 1) {
return -1;
} else {
for (int j = i; j < last; j++) {
element[j - 1] = element[j];
}
last--;
return 1;
}
}
/**
* 获取元素
*
* @param i
* @return
*/
public int get(int i) {
if (i <= 0 || i > last + 1) {
return -1;
} else
return element[i - 1];
}
}
主函数:
public class Order {
public static void main (String args[])
{
OrderTable orderTable=new OrderTable();
for (int i = 1; i <= 50; i++)
{
orderTable.insert(i * 2, i);
}
for (int i = 1; i <= 50; i++)
{
System.out.print(orderTable.get(i)+ " ");
if (i % 10 == 0)
System.out.println();
}
orderTable.delete(1);
for (int i = 1; i <= 50; i++)
{
System.out.print(orderTable.get(i)+ " ");
if (i % 10 == 0)
System.out.println();
}
}
}
运行结果:
以上用了三种语言实现了顺序表的基本运算。