基础闯关记-线性表

线性表

什么是线性表

线性表的定义:线性表是n个具有相同特性的数据元素的有限序列。线性表是一种最简单,最基本,也是最常用的一种逻辑线性结构。

一个线性表通常记为:(A1,A2,A3 …… An)。其中n为表长;当n为0时,称为空表。

线性表的存储方式

注意,线性表是一种逻辑线性结构,所以我们的实现只要保证逻辑上是线性就可以。有两种存储方式

顺序存储

顺序存储方式:在物理内存上利用一片连续,相邻的空间来存放数据

我们的内存条是有编号的,顺序存储的方式就是找到在一段连续空闲的编号内存中存储线性表数据,数据组织方式如下图所示

image

优点:随机查找速度快,CPU指令支持偏移量访问元素,所以访问速度相当快

缺点:插入和删除慢,一般要移动很多元素。扩容难,有可能系统找不到连续空间了。

链式存储

链式存储方式:在物理上,利用不连续,随机,零碎的空间来存放数据

因为物理上元素没有逻辑关联,所以我们需要通过指针将相邻元素连接起来,这种方式不要求利用的内存编号是连续的。

image

优点:插入和删除简单,不需移动元素。扩容简单,只需要随机找到一个内存块就行

缺点:查找慢,需要遍历整个线性表

线性表的基本操作

通常情况下,线性表满足的基本操作由:

函数 注释
InitList(List *L) 初始化一个空线性表
DestoryList(List *L) 销毁一个线性表
Find(List *L, int i ) 根据位序K,返回相应元素
Find( int X, List *L ) 在线性表L中查找X的第一次出现位置
Insert(*List L, int i, int X) 在位序i前插入一个新元素X
Delete(List *L, int i ) 删除指定位序i的元素
int Length( List *L ) 返回线性表L的长度n

线性表顺序存储实现

线性表最简单的就是使用顺序存储的方式存储每个元素,我们可以只记录序列的首地址,然后通过地址偏移量就能访问到所有元素。比如访问第i个元素,就是将首地址+i的形式访问。

定义头文件

按照程序=数据结构+算法思路,我们定义一个顺序存储下线性表的结构体

typedef struct {
    int *p;//线性表元素起始地址
    int len;//线性表当前长度
    int max_len;//线性表最大长度
} Splist;

我们再定义线性表需要支持的算法,这些定义可以统一放到头文件list.h

#define LIST_INIT_SIZE 10

//定义线性表结构
typedef struct {
    int *p;//线性表元素起始地址
    int len;//线性表当前长度
    int max_len;//线性表最大长度
} Splist;

//声明线性表支持的操作算法
int InitList( Splist *l );
int DestoryList(Splist *l);
int Insert(Splist *l, int i, int e);
int Delete(Splist *l, int i);
int Find(Splist *l, int i);
int Length(Splist *l);

实现主体算法

线性表整个的实现也不复杂,需要注意的在插入操作时考虑内存不足的情况,实现代码list.c

#include<stdio.h>
#include<stdlib.h>
#include "list.h"
int InitList( Splist *l ){
	l->p = (int *) malloc(LIST_INIT_SIZE * sizeof(int));
	if(!(l->p)){
		return 0;
	}
	l->len = 0;
	l->max_len = LIST_INIT_SIZE;
	return 1;
}

int DestoryList(Splist *l){
	free(l->p);
	l->p = NULL;
	l->len = 0;
	l->max_len = 0;
}

int Insert(Splist *l, int i, int e){
	if(i<0 || i > l->len){
		return 0;
	}

	//内存不够
	if(l->len >= l->max_len){
		int *newP = realloc(l->p, sizeof(int) * (l->max_len + 1));
		if(!newP){
			printf("扩容失败");
			return 0;
		}
		//扩容成功,更新结构体数据
		l->p = newP;
		l->max_len = l->max_len + 1;
	}

	//正常插入
	int k = l->len -1;
	while(i <= k && k >=0){
		*(l->p + k + 1) = *(l->p + k);
		k--;
	}
	*(l->p+i) = e;
	l->len ++;
	return 1;
}

int Delete(Splist *l, int i){
	if(i<0 || i>l->len){
		return 0;
	}

	int k=i;
	while(k < l->len){
		*(l->p+k) = *(l->p+k+1);
		k++;
	}
	l->len --;

	return 1;
}

int Find(Splist *l, int i){
	if(i<0 || i>l->len){
		return 0;
	}
	int *k = l->p + i;
	printf("%d\n", *k);
	return 1;
}

int Length(Splist *l){
	return l->len;
}

测试

我们可以编写一个测试文件
注意,我们在写测试文件的时候,一定要让线性表的长度大于15,这样才能有扩容的效果。

#include<stdio.h>
#include<stdlib.h>
#include "list.h"
void main(){
    Splist *l = (Splist *) malloc(sizeof(Splist));
    InitList(l);
    int i;
    for(i=0; i< 15; i++){
        Insert(l, i, i);
    }
    Delete(l,2);
    for(i=0; i<Length(l); i++){
        Find(l, i);
    }
    DestoryList(l);
}

线性表的链式存储实现

在前面提到的数组实现的线性表中,有一个很大的缺点就是插入和删除元素的时候一个线性开销。所以,我们可以选择使用链式存储来实现,即不要求逻辑上相邻的两个元素物理上也相邻;通过“链”建
立起数据元素之间的逻辑关系,插入、删除不需要移动数据元素,只需要修改“链”。我们定义链式存储实现的线性表结构体:

//定义线性表结构
struct Node{
        int value;
        struct Node *next;
};
typedef struct Node Splist;

首先定义了链式存储中的每一个节点的结构Node,里面有数据,另外有一个指针域,表示指向下一个节点。这里我们简单起见,假定节点里保存的数据类型为int。最后定义一个Node指针的别名Splist。

定义头文件

#define LIST_INIT_SIZE 10

//定义线性表结构
struct Node{
        int value;
        struct Node *next;
};
typedef struct Node Splist;

//声明线性表支持的操作算法
int InitList( Splist *l );
int DestoryList(Splist *l);
int Insert(Splist *l, int i, int e);
int Delete(Splist *l, int i);
int Find(Splist *l, int i);
int Length(Splist *l);

实现主体算法

#include<stdio.h>
#include<stdlib.h>
#include "list.h"
int InitList( Splist *l ){
    l->next = NULL;
}

int DestoryList(Splist *l){
	Splist *n = l;
	while(l){
		n = l->next;
		free(l);
		l = n;
	}
	return 1;
}

int Insert(Splist *l, int i, int e){
	//生成新的节点
	Splist *newNode = (Splist *)malloc(sizeof(Splist));
	if(!newNode){
		return 0;
	}
	newNode->value = e;
	newNode->next = NULL;

	//寻找插入位置
	Splist *n = l;
	int k = 0;
	while(k < i){
		n = n->next;
		k++;
	}
	newNode->next = n->next;
	n->next = newNode;
	return 1;	
}

int Delete(Splist *l, int i){
	//寻找删除的位置
	Splist *n = l;
	int k = 0;
	while(k <= i){
		n = n->next;
		k++;
	}
	n->next = n->next->next;	
	return 1;
}

int Find(Splist *l, int i){
	Splist *n = l;
	int k = 0;
	while(k <= i){
		n = n->next;
		k++;
	}
	
	printf("%d\n", n->value);
	return 1;
}

int Length(Splist *l){
	Splist *n = l;
	int k=0;
	while(n->next){
		k++;	
		n = n->next;
	}
	return k;
}

测试

#include<stdio.h>
#include<stdlib.h>
#include "list.h"
void main(){
	Splist *l = (Splist *) malloc(sizeof(Splist));
	InitList(l);
	int i;
	for(i=0; i< 15; i++){
		Insert(l, i, i);
	}
	Delete(l,2);
	for(i=0; i<Length(l); i++){
		Find(l, i);
	}
	DestoryList(l);
}

参考

浩然 《大数据就是这么任性》

posted @ 2017-08-06 23:31  一路既往  阅读(310)  评论(0)    收藏  举报