线性表的顺序存储结构——顺序表
线性表是具有享用特性的数据元素的一个有限序列,线性表的顺序存储结构简称为顺序表。
顺序表的数据类型
typedef struct
{
ElemType data[MaxSize];
int length;
}SqList;
typedef简单用法
typedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。 在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。
typedef的使用方法如下:
typedef existing_type new_type_name ;
注意:typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。
关于引用的简单说明
向函数传递参数的引用调用方法,把引用的地址复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
按引用传递值,参数引用被传递给函数,就像传递其他值给函数一样。因此相应地,在下面的函数 swap() 中,您需要声明函数参数为引用类型,该函数用于交换参数所指向的两个整数变量的值。
// 函数定义
void swap(int &x, int &y)
{
int temp;
temp = x; /* 保存地址 x 的值 */
x = y; /* 把 y 赋值给 x */
y = temp; /* 把 x 赋值给 y */
return;
}
引用的优点:比起传指针,传引用更加方便; 比起传值,传引用速度更快,节省空间。但是引用一旦定义就不能再引用其他变量,直至该引用灭亡。
线性表代码实现:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#ifdef WIN32
#include <malloc.h>
#else
#include <sys/malloc.h>
#endif
using namespace std;
const int MaxSize = 50;
typedef int ElemType;
typedef struct
{
ElemType data[MaxSize];
int length;
}SqList;
//SqList *L 为指针变量, SqList & 为引用, SqList *&为指针的引用
//注意没有引用的指针,因为引用本身不是变量,不在内存中占有空间
void CreateList(SqList *&L, ElemType a[], int n);
void InitList(SqList *&L);
void DestroyList(SqList *&L);
bool ListEmpty(SqList *L);
int ListLength(SqList *L);
void DispList(SqList *L);
bool GetElem(SqList *L, int i, ElemType &e);
int LocateElem(SqList *L, ElemType e);
bool ListInsert(SqList *&L, int i, ElemType e);
bool ListDelete(SqList *&L, int i, ElemType &e);
void Delnodel(SqList *&L, ElemType x);
void Partition(SqList *&L);
void QuickSort(SqList *&L, int left, int right);
void Change(ElemType &a, ElemType &b);
int main(void)
{
SqList *L;
/*
int a[10] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
CreateList(L, a, 10);
DispList(L);
ListInsert(L, 3, 10);
DispList(L);
ElemType e;
ListDelete(L, 2, e);
DispList(L);
delnodel(L, 10);
DispList(L);
*/
int a[10] = {5, 1, 3, 7, 9, 2, 4, 6, 8, 10};
CreateList(L, a, 10);
DispList(L);
//Partition(L);
QuickSort(L, 0, 10);
DispList(L);
return 0;
}
//建立顺序表 时间复杂度O(N)
void CreateList(SqList *&L, ElemType a[], int n)
{
L = (SqList *)malloc(sizeof(SqList)); //分配存储线性表的空间
for (int i = 0; i < n; i++)
L->data[i] = a[i]; //将数组a中的元素存放到L中
L->length = n; //设置线性表的长度
}
//初始化线性表 时间复杂度O(1)
void InitList(SqList *&L)
{
L = (SqList *)malloc(sizeof(SqList)); //分配存储线性表的空间
L->length = 0; //置空线性表的长度为0
}
//销毁线性表 时间复杂度O(1)
void DestroyList(SqList *&L)
{
free(L); //释放L所指的顺序表空间
L = NULL; //将L指向NULL(保障安全)
}
//求线性表的长度 时间复杂度O(1)
int ListLength(SqList *L)
{
return (L->length);
}
//判断线性表是否为空表 时间复杂度O(1)
bool ListEmpty(SqList *L)
{
return (L->length == 0);
}
//输出线性表 时间复杂度O(N)
void DispList(SqList *L)
{
if (ListEmpty(L)) //判断线性表是否为空,为空则抛出提示信息
{
printf("线性表为空表!\n");
return;
}
for (int i = 0; i < L->length; i++) //线性表若非空,则输出线性表的元素
printf("%d ", L->data[i]);
printf("\n");
}
//求线性表中的某个数据元素值(i为逻辑索引) 时间复杂度O(1)
bool GetElem(SqList *L, int i, ElemType &e)
{
if (i < 1 || i > L->length) //输入的索引有误
return false;
e = L->data[i-1]; //向引用e返回元素值
return true;
}
//按元素值查找(返回逻辑索引) 时间复杂度O(N)
int LocateElem(SqList *L, ElemType e)
{
int i;
for (i = 0; i < L->length; i++)
{
if (e == L->data[i]) //若找到该元素则退出寻找
break;
}
if (i == L->length) //未找到
return -1;
else
return i+1;
}
//插入数据元素 时间复杂度O(N)
bool ListInsert(SqList *&L, int i, ElemType e)
{
if (i < 1 || i > L->length+1) //输入的索引有误
return false;
i--;
for (int j = L->length; j > i; j--) //将data[i]及后面的元素后移一个位置
L->data[j] = L->data[j-1];
L->data[i] = e; //将该元素插入
L->length++; //线性表长度加一
return true;
}
//删除数据元素 时间复杂度O(N)
bool ListDelete(SqList *&L, int i, ElemType &e)
{
if (i < 1 || i > L->length) //输入的索引有误
return false;
i--;
e = L->data[i]; //向引用e返回所删除的元素值
for (int j = i; j < L->length-1; j++) //将data[i]之后的元素前移一个位置
L->data[j] = L->data[j+1];
L->length--; //线性表长度减一
return true;
}
//删除线性表中所有值为x的元素 时间复杂度O(N)
void Delnodel(SqList *&L, ElemType x)
{
int k = 0;
for (int i = 0; i < L->length; i++)
{
if (L->data[i] != x) //若当前元素不为x,则将其插入到L中
{
L->data[k] = L->data[i];
k++;
}
}
L->length = k;
}
//使用引用交换两个变量的值 时间复杂度O(1)
void Change(ElemType &a, ElemType &b)
{
//三变量法
ElemType t;
t = a;
a = b;
b = t;
}
//以第一个元素为分界线,将表中所有小于等于它的元素移到该基准的前端,大于的则移动到后面
//时间复杂度O(N)
void Partition(SqList *&L)
{
int i = 0, j = L->length-1;
ElemType pivot = L->data[0];
while (i < j)
{
while (i < j && L->data[j]>pivot)
j--;
while (i < j && L->data[i]<=pivot)
i++;
if (i < j)
Change(L->data[i], L->data[j]);
}
Change(L->data[0], L->data[i]);
}
void QuickSort(SqList *&L, int left, int right)
{
//如果left不小于right,需要排序的部分只有一个元素,退出排序
if (left >= right)
return;
int i, j;
ElemType pivot = L->data[left]; //设置左边的元素为基准点
i = left;
j = right;
while (i < j)
{
//要让右边的向左移动,请想一想为什么
//j向左移,找到一个比p小的元素
while (i < j && L->data[j] >= pivot)
j--;
//i向右移,找到一个比p大的元素
while (i < j && L->data[i] <= pivot)
i++;
//i和j交换
if (i < j)
Change(L->data[i], L->data[j]);
}
L->data[left] = L->data[i];
L->data[i] = pivot;
//对序列中,i左边的元素实施快速排序
QuickSort(L, left, i-1);
//对序列中,i右边的元素实施快速排序
QuickSort(L, i+1, right);
}
顺序表的插入、删除、快排需要自己在纸上模拟一下,以后的链表、栈等数据结构都要养成模拟的好习惯o(∩_∩)o ~