二、线性结构(1线性表)
2.1 线性表的顺序存储实现
2.1.1 数据结构定义
typedef struct LNode *List;
struct LNode{
ElementType Data[MAXSIZE];
int Last;
};
struct LNode L;
List Prtl;
- MAXSIZE为Data数组的最大长度(确定值)
- Last指向数组中存储的最后一个元素n,下标为n-1
- 线性表的长度为:L.Last+1 或 Ptrl->Last+1
2.1.1.1 主要操作
- List MakeEmpty();//初始化一个空线性表L;
- ElementType FindKth( int K, List L );//根据位序K,返回相应元素;
- int Find( ElementType X, List L ):在线性表L中查找X的第一次出现位置;
- void Insert( ElementType X, int i, List L):在位序i前插入一个新元素X;
- void Delete( int i, List L ):删除指定位序i的元素;
- int Length( List L ):返回线性表L的长度n。
2.1.1.2 主要操作实现
1. 初始化(建立空的顺序表)
List MakeEmpty()
{
List Ptrl;
Ptrl = ( List )malloc( sizeof(struct LNode) );//申请内存空间
Ptrl->Last = -1;//空表没有元素,则长度为-1,0表示有一个元素
return Ptrl;
}
2 查找
查找X值在表中的位置,返回位置序号
int Find( Elementype X, List Ptrl )
{
int i = 0;
while( i <= Ptrl->Last && Ptrl -> Data[i] != X )
i++;
if( i > Ptrl->Last )
return -1; //没有查找到对应值,返回-1
else
return i; //找到返回后的之,返回存储位置
}
- 查找成功的平均比较次数为(n+1)/2
- 平均十进性能为O(n)
3 插入
第i( 1 <= i <= n+1)个位置上插入一个值为X的新元素
void Insert( ElementType X, List Ptrl )
{
int j;
//表空间已满,不能再插入
if( Ptrl->Last == MAXSIZE-1){
printf( "表满" );
return;
}
//检查插入位置是否合法
if( i < 1 || i > Ptrl->Last+2 ){
printf( "位置不合法" );
return;
}
//以上没有问题,进行插入操作
for( j = Ptrl->Last; j >= i-1; j--)
Ptrl->Data[j+1] = Ptrl->Data[j];
Ptrl->Data[i-1] = X;
Ptrl->Last++;
return;
}
- i < Ptrl->Last+2 的由来
- 假设链表共有n个元素
- Ptrl->Last指向的是第n个元素,即Ptrl->Data[n-1]元素
- i < Ptrl->Last+2,即 i < n-1+1+1 , i < n+1 ,则可以有 i = n+1
- 在向i的位置插入X时需要对i-1处理,则插入到Ptrl-Data[i-1],即插入到Ptrl->Data[n]的位置
- 没有留下空位,则可以插入
4 删除
void Delete( int i, List Ptrl )
{
int j;
//判断删除的元素是否在数组元素范围之内
if( i <1 || i > Ptrl->Last+1 ){
printf( "不存在第%d个元素", i );
return;
}
//删除指定元素
//实现方式是将其后元素依次前移
for( j = i; j <= Prtl->Last; j++ ){
Ptrl->Data[i-1] = Ptrl->Data[i];
}
Ptrl->Last--;//指向删除后的最后元素
return;
}
2.2 线性表的链式存储实现
2.2.1 数据结构定义
typedef struct LNode *List;
struct LNode{
ElementType Data;
List Next;
};
struct LNode L;
List Ptrl;
- 不要求逻辑上相邻的两个元素物理上也相邻
- 通过链建立数据元素之间的逻辑关系"Next"
- 插入、删除不需要移动数据元素,只需要修改“链”“Next”
- 查找元素相对较麻烦
2.1.1.1 主要操作
-
List MakeEmpty();//初始化一个空线性表L;
-
ElementType FindKth( int K, List L );//根据位序K,返回相应元素;
-
int Find( ElementType X, List L ):在线性表L中查找X的第一次出现位置;
-
void Insert( ElementType X, int i, List L):在位序i前插入一个新元素X;
-
void Delete( int i, List L ):删除指定位序i的元素;
-
int Length( List L ):返回线性表L的长度n。
2.1.1.2 主要操作实现
1 初始化(建立空的顺序表)
//随机产生n个元素的值,建立带表头节点的单链表线性表L(头插法)
void MakeEmpty( List *L, int n )
{
List Ptrl;
int i;
srand(time(0));//初始化随机数种子
*L = ( List )malloc( sizeof(struct LNode) );//申请内存空间
*L->Next = NULL;//先建立一个带头节点的单链表
for( i = 0; i < n; i++){
Ptrl = (List)malloc(sizeof(struct LNode));//生成新节点
Ptrl->Data = rand()%100+1;//随机生成100以内的数字填充元素内容
Ptrl->Next = (*L)->Next;
(*L)->Next = Ptrl;//插入到表头
}
}
2 求表长
int Length( List Ptrl)
{
List p = Ptrl;//p指向表的第一个节点
int j = 0;
while(p){
p = p->Next;
j++;//当前p指向的是第j个节点
}
return j;
}
- 平均时间性能为O(n)
3 查找
3.1 按序号查找
List FindKth( int K, List Ptrl )
{
List p = Ptrl;
int i = 1;
while( p != NULL && i < K){
p = p->Next;
i++;
}
if( i == K )
return p;//找到第K个,返回指针
else
return NULL;//否则返回空值
}
- 平均时间性能为O(n)
3.2 按值查找
List Find( ElementType X, List Ptrl )
{
List p = Ptrl;
while( p != NULL && p->Data != X ){
p = p->Next;
}
return p;
}
- 平均时间性能为O(n)
4 插入操作
- 在第 i - 1 (1 <= i <=n+1)个结点后插入一个值为X的新结点
List Insert( ElementType X, int i, List Ptrl )
{
List p, s;
//新结点插入在表头
if( i == 1 ){
s = (List)malloc(sizeof(struct LNode));//申请新结点
s->Data = X;//装填新结点
s->Next = Ptrl;
return s;
}
p = FindKth(i-1,Ptrl);//查找第i-1个结点
if(p == Null){
printf("参数i错误");//第i-1个不存在,不能插入
return NULL;
}
else{
s = (List)malloc(sizeof(struct LNode));
s->Data = X;
s->Next = p->Next;
p->Next = s;
return Ptrl;
}
}
- 平均查找次数为n/2
- 平均是按性能为O(n)
5 删除
- 删除链表的第 i ( 1 <= i <= n )个位置上的结点
List Delete( int i, List Ptrl )
{
List p, s;
//若要删除的是表的第一个结点
if(i == 1){
s = Ptrl;
if(Ptrl != NULL)
Ptrl = Ptrl->Next;//删除头结点后,头结点指向之前的第二个结点
else
return NULL;
free(s);//释放掉对应想要删除结点的内存空间,即删除结点
return Ptrl;
}
p = FindKth( i-1, Ptrl);
if( p == NULL ){
printf("第%d个结点不存在", i-1);
return NULL;
}
else if( p->Next == NULL){
printf("第%d个结点不存在", i);
return NULL;
}
else {
s = p->Next;
p->Next = s->Next;
free(s);
return Ptrl;
}
}
- 平均查找次数为n/2
- 平均时间性能为O(n)
2.1.2 参考资料
2.1.2.1 malloc函数
malloc说明
1、malloc的全称是memory allocation(动态内存分配)
2、malloc函数是一种分配长度为num_bytes字节的内存块的函数,可以向系统申请分配指定size个字节的内存空间。
1、返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针。
char *Ptr = NULL;
Ptr = (char *)malloc(100 * sizeof(char));
malloc用法
1、使用前要申明:#include <stdlib.h>或者#include <malloc.h>
2、void *malloc(long NumBytes):
该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。分配失败的原因,应该有多种比如说空间不足就是一种。
3、void free(void *FirstByte):
该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。
malloc重点
1、对返回值进行检查:分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。
2、使用完毕释放内存:当内存不再使用时,应使用free()函数将内存块释放。
malloc函数与new函数区别
new返回指定类型的指针,并且可以自动计算所需要的大小。
int *p;
p = new int; //返回类型为int *类型,分配的大小为sizeof(int)
p = new int[100]; //返回类型为int *类型,分配的大小为sizeof(int) * 100
而malloc则必须由我们计算字节数,并且在返回的时候强转成实际指定类型的指针。
int *p;
p = (int *)malloc(sizeof(int));
free(p);
- malloc的实参是sizeof(int),用于指明一个整形数据需要的大小,如果我们写成:p = (int
*)malloc(1),那么可以看出:只是申请了一个字节的空间,如果向里面存放了一个整数的话,将会占用额外的3个字节,可能会改变原有内存空间中的数据; - malloc只管分配内存,并不能对其进行初始化,所以得到的一片新内存中,值是随机的。一般意义上:我们习惯性的将其初始化为NULL。当然,也可以用memset函数的。
memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。
void *memset(void *s, int c, size_t n);
char a[4]; memset(a,'1',4);cout << a[i]; 1 1 1 1
- s指向要填充的内存块。
- c是要被设置的值。
- n是要被设置该值的字符数。
- 返回类型是一个指向存储区s的指针。