基础和线性表

1 数据结构

  解决问题方法的效率,跟数据的组织方式有关

  解决问题方法的效率,跟空间的利用效率有关

  解决问题方法的效率,跟算法的巧妙程度有关

  数据结构

    数据对象在计算机中的组织方式

      逻辑结构

      物理存储结构

  数据对象必定与一系列加在其上的操作相关联

  完成这些操作所用的方法就是算法

  抽象数据类型(Abstract Data Type)

    数据类型

      数据对象集

      数据集合相关联的操作集

    抽象: 描述数据类型的方法不依赖与具体实现

      与存放数据的机器无关

      与数据存储的物理结构无关

      与实现操作的算法和编程语言无关

  只描述数据对象集和相关操作集是什么, 并不涉及如何做到的问题

2 算法

  算法

    一个有限指令集

    接受一些输入(或者没有输入)

    产生输出

    一定在有限步骤之后终止

    每一条指令必须

      有充分明确的目标, 不可以有歧义

      计算机能处理的范围之内

      描述应不依赖于任何一种计算机语言以及具体的实现手段

  判定算法好换的依据-复杂度

  空间复杂度S(n)

  时间复杂度T(n)

  一般来说关注的是最坏情况的复杂度平均复杂度

  复杂度的渐进表示法      

  1 < logn < n <nlogn < n2 <2n < n!

3 最大子列和

  最大子列和问题就是, 给定一个数字序列, 求其中按顺序截取的子序列和最大的

  1) 算法1, 分三层遍历, 第一层遍历序列, 第二层遍历当前之后的, 第三层计算序列的和

    算法1的具体实现

def algo_1(my_list):
    max_sum = 0
    size = len(my_list)
    for i in range(size):
        for j in range(i,size):
            current_sum = 0
            for k in range(i,j+1):
                current_sum += my_list[k]
            if current_sum >= max_sum:
                max_sum = current_sum
    print(max_sum)

  2) 算法2, 分两层遍历, 第一层遍历, 第二计算值

    具体代码如下

def algo_2(my_list):
    max_sum = 0
    size = len(my_list)
    for i in range(size):
        current_sum = 0
        for j in range(i,size):
            current_sum += my_list[j]
            if current_sum > max_sum:
                max_sum = current_sum
    print(max_sum)

  3) 算法3, 分而治之

    分而治之实现比较复杂

    基本思想就是, 分成两个部分, 求出左边最大的, 求出右边最大的, 求出跨边界最大的, 三者最大的就是最大的

    算法内容是:

      先中分, 再中分,不断中分

      从最小两个分部开始, 选择最大的值

      在联合就近第二小的选择, 处理跨边界, 从边界出发, 得到向左延续的1格, 2格..求出最大的, 右边也是, 然后两个最大的合在一起就是边界最大

      不断重复直到最后

  4) 算法4, 在线处理

    时间复杂度为o(n), 应该是最快的时间复杂度了

    该算法的特点的可以等待输入就可以获得当前序列的最大子序列, 这也是在线处理的由来

    具体的思路是, 抓住子序列的特点的连续的

    要使得连续序列能够增大, 则部分和应该是正数, 当出现负数和式, 需要舍弃值重新计算序列

    具体实现如下

def algo_4(my_list):
    max_sum = 0
    current_sum = 0
    size = len(my_list)
    for i in range(size):
        current_sum += my_list[i]
        if current_sum > max_sum:
            max_sum = current_sum
        elif current_sum < 0:
            current_sum = 0
    print(max_sum)

4 线性表

线性结构最简单的就是线性表

4.1 多项式的表示

  多项式的主要信息有两个, 一个是x的次数, 一个是对应的系数

  1) 方法1, 数组方式

    数组按照索引的方式, 索引对应x的次数, 系数就存放在对应的数组位置

    优点: 计算十分方便

    缺点: 浪费空间

  2) 方法2: 二维数组方式

    数组里面再存一个数组, 数组里面存放系数和次数

    为了便于计算, 存储的时候要按照次数按顺序存入

    计算方式:

      取出两个多项式的第0项目, 比较系数大小, 如果不相同, 输出大的, 然后获得对应多项式的第1项目, 在比较系数进行运算; 如果相同直接运算输出;

     优点: 不用存储系数为0的项目, 节省空间

  3) 方法3: 使用链表存储

    定义一个结构体, 内容有次数, 系数, 下一个指针

    计算方式同方法2

4.2 线性表以及顺序存储

  一般来说, 线性表的问题都是有两种方式, 要么是数组, 要么是链表

  线性表: 由类型数据元素构成有序序列的线性结构

    表中元素的个数恒伟线性表的长度

    线性表没有元素时, 称为空表

    表其实位置称为表头, 表结束位置称为表尾

  线性表的ADT表示

    

4.2.1 线性表的顺序存储实现

  利用数组的连续存储空间顺序存放线性表的各个元素

  使用数组的方式来构建线性表

  数据类型表示

typedef struct{
	ElementType Data[MAXSIZE];
	int Last; 
}List;

List L,*PtrL;

  线性表的主要操作

  1) 初始化

List *MakeEmpty(){
	List *PtrL;
	PtrL = (List *)malloc(sizeof(List));
	PtrL->Last = -1;
	return PtrL;
}

  2) 查找

int Find(ElementType X, List *PtrL)
{
	int i = 0;
	while( i<=PtrL->Last && PtrL->Data[i]!=X )
		i++;
	if( i> PtrL->Last)
		return -1;
	else
		return i;
}

  查找的平均次数是 (n+1)/2

  平均时间性能为 O(n)

  3) 插入

  在第i(1<=i<=n+1)个位置插入元素X

  对应在数据上, 就是插入到索引 i-1 的位置

  需要遵循的是先移动再插入

  实现为

void Insert(ElementType X, int i, List *PtrL)
{
	int j;
	if(PtrL->Last == MAXSIZE-1){
		printf("表满了");
		return ;
	}
	if( i < 1 || 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;
}

  4) 删除

  删除第i(1<=i<=n)个元素  

  后面的元素依次往前移动

  实现

void Delete( int i, List *PtrL)
{
	int j;
	if( i <1 || PtrL->Last+1 ){
		printf("不存在第%d个元素", i);
		return ;
	}
	for( j=1; j<=PtrL->Last; j++)
		PtrL->Data[j-1] = PtrL->Data[j];
	PtrL->Last--;
	return ;
}

  平均移动次数为(n-1)/2

  平均时间性能为O(n)

4.2.2  线性表的链式存储实现  

  链式存储不需要物理存储上也是相邻存储

  元素之间通过指针来链接

  定义数据结构

typedef struct Node
{
	ElementType Data;
	struct Node *Next;
}List;
List L, *PtrL;

  主要的操作实现

  1) 求表长度

int Length(List *PtrL)
{
	List *p = PtrL;
	int j = 0;
	while(p){
		p = p->Next;
		j++
	}
	return j;
}

  时间复杂度为O(n)

  2) 查找

  按照序号查找

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;
	else
		return NULL;
}

  按值查找

List *Find(ElementType X, List *PtrL){
	List *p = PtrL;
	while( p!=NULL && p->Data!=X)
		p = p -> Next;
	return p;
}

  平均时间复杂度为O(0)

  3) 插入

  在第i-1(1<=i<=n+1)个结点后插入一个值为X的新结点

  插入的步骤

    1) 创建一个新的节点, 用s指向

    2) 找到i-1个节点, 用p执行

    3) 修改指针

s->Next = p->Next;
p->Next = s;

  顺序不能交换, 不然的话就找不到第i个节点的指针了

  

  4) 删除

  删除第i[1,n]个位置上的节点

  步骤

    1) 找到i-1个节点, 用p指向

    2) 用s指向被删除的节点

s = p->next;

    3) 修改p指针

p->next = s->next;

    4) 释放s的空间

  

4.2.3 广义表和多重链表

  之前的一元多项式可以用顺序表表示

  如果是二元多项式的话, 就可以同样的先看成是关于x的一元多项式, 然后x的系数是关于y的一元多项式

  

  广义表:

    线性表的推广

    在广义表中元素可能是另一个广义表, 而相对的线性表中就是一个单元素

  

  多重链表

    链表中的节点可能同时隶属于多个链

    多重链表中的节点有多个指针域, 但是不是有多个指针域就是剁成链表, 判断的依据是不是指向自身的

  可以用典型的多重链表-十字链表来存储稀疏矩阵

    只存储非0项, 数据域为: 行, 列, 数值

    每个节点通过两个指针域, 把同行同列串起来, 也就是Right和Down指针

  

  

 

posted @ 2017-06-01 16:45  weihuchao  阅读(396)  评论(0编辑  收藏  举报