精华内容
下载资源
问答
  • 二项队列简单实现

    2017-05-18 12:33:57
    二项队列 二项队列也优先队列...对于插入操作,平均花费常数时间什么是二项队列 与左堆和二叉堆不同的是二项队列不是树,而是树集合,也就是森林.  这个森林中,每个高度最多只有一棵树. 这里不再详细

    二项队列

      二项队列也是优先队列的一种实现方式,之前有用左式堆和二叉堆来实现优先队列,不过二项队列与左式堆和二叉堆的不同在于二项队列能有效的支持合并/插入/DeleteMin操作,每次操作的最坏运行时间是O(log n),对于插入操作,平均是花费常数时间

    什么是二项队列

      与左式堆和二叉堆不同的是,二项队列不是树,而是树的集合,也就是森林.
      这个森林中,每个高度最多只有一棵树.

    这里不再详细说明二项队列的思路,如有需要,可以自行百度(因为百度上已经有很多比较详细的了)

    代码实现

    
    #include <stddef.h>
    #include <math.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    typedef struct BinNode *Positon, *BinTree;
    typedef struct Collection *BinQueue;
    typedef int ElementType;
    
    int MaxTrees = 100000;
    int Capacity = 200000;
    struct BinNode {
       ElementType Element;
       Positon LeftChild;
       Positon NextSibling;
    };
    
    struct Collection {
       int CurrentSize;
       BinTree TheTrees[1000000];
    };
    
    void Error(char *message) {
       printf("%s\n", message);
    }
    
    int IsEmpty(BinQueue H) {
       return H->CurrentSize == 0;
    }
    
    BinQueue Initialize() {
       BinQueue H = malloc(sizeof(struct Collection));
       H->CurrentSize = 0;
    
       int i;
       for (i = 0; i <= MaxTrees; i++) {
           H->TheTrees[i] = NULL;
       }
       return H;
    }
    
    BinTree CombineTrees(BinTree T1, BinTree T2) {
       if (T1->Element > T2->Element)
           return CombineTrees(T2, T1);
       T2->NextSibling = T1->LeftChild;
       T1->LeftChild = T2;
       return T1;
    }
    
    /* Merge two binomial queues */
    /* Not optimized for early termination */
    /* H1 contains merged result */
    BinQueue Merge(BinQueue H1, BinQueue H2) {
       BinTree T1, T2, Carry = NULL;
       int i, j;
    
       if (H1->CurrentSize + H2->CurrentSize > Capacity)
           Error("Merged would exceed capacity");
    
       H1->CurrentSize += H2->CurrentSize;
       for (i = 0, j = 1; j <= H1->CurrentSize; i++, j *= 2) {
           T1 = H1->TheTrees[i];
           T2 = H2->TheTrees[i];
    
           switch (!!T1 + 2 * !!T2 + 4 * !!Carry) {
               case 0:/* No trees */
               case 1:/* Only H1 */
                   break;
               case 2:/* Only H2 */
                   H1->TheTrees[i] = T2;
                   H2->TheTrees[i] = NULL;
                   break;
               case 4:/* Only Carry */
                   H1->TheTrees[i] = Carry;
                   Carry = NULL;
                   break;
               case 3:
                   Carry = CombineTrees(T1, T2);
                   H1->TheTrees[i] = H2->TheTrees[i] = NULL;
                   break;
               case 5:
                   Carry = CombineTrees(T1, Carry);
                   H1->TheTrees[i] = NULL;
                   break;
               case 6:
                   Carry = CombineTrees(T2, Carry);
                   H2->TheTrees[i] = NULL;
                   break;
               case 7:
                   H1->TheTrees[i] = Carry;
                   Carry = CombineTrees(T1, T2);
                   H2->TheTrees[i] = NULL;
                   break;
           }
    
       }
       return H1;
    }
    
    
    ElementType DeleteMin(BinQueue H) {
       int i, j;
       int MinTree;
       BinQueue DeletedQueue;
       Positon DeletedTree, OldRoot;
       ElementType MinItem;
    
       if (IsEmpty(H)) {
           Error("Empty binomial queue");
           return -INFINITY;
       }
    
       MinItem = INFINITY;
       for (i = 0; i < MaxTrees; i++) {
           if (H->TheTrees[i] &&
               H->TheTrees[i]->Element < MinItem) {
               MinItem = H->TheTrees[i]->Element;
               printf("%d\n", MinItem);
               MinTree = i;
           }
       }
    
       DeletedTree = H->TheTrees[MinTree];
       OldRoot = DeletedTree;
       DeletedTree = DeletedTree->LeftChild;
       free(OldRoot);
    
       DeletedQueue = Initialize();
       DeletedQueue->CurrentSize = (1 << MinTree) - 1;
       for (j = MinTree - 1; j >= 0; j--) {
           DeletedQueue->TheTrees[j] = DeletedTree;
           DeletedTree = DeletedTree->NextSibling;
           DeletedQueue->TheTrees[j]->NextSibling = NULL;
       }
    
       H->TheTrees[MinTree] = NULL;
       H->CurrentSize -= DeletedQueue->CurrentSize + 1;
    
       Merge(H, DeletedQueue);
       return MinItem;
    }
    
    int main() {
       int i;
       BinQueue Q[1000];
       for (i = 0; i < 1000; i++) {
           Positon P = malloc(sizeof(struct BinNode));
           P->Element = i;
           P->NextSibling = P->LeftChild = NULL;
           Q[i] = Initialize();
           Q[i]->CurrentSize = 1;
           Q[i]->TheTrees[0] = P;
       }
       BinQueue result = Merge(Q[0], Q[1]);
       for (i = 2; i < 1000; i++) {
           result = Merge(result, Q[i]);
       }
       int j = DeleteMin(result);
       printf("%d\n", j);
       return 0;
    }
    

    Merge

      Merge操作是按高度从小到大依次合并

    Deletemin

      遍历一遍二项队列中的树根,找到最小的那个,然后把该二项树打散成若干哥二项树,构造成一个新的二项队列,然后删掉这个二项树构造出另一个新的二项队列,最后合并这两个新的二项队列

    • 代码摘自 数据结构与算法分析第二版 ,基于书上的代码增添了书中未完善的部分,提供了一个main函数用于测试
    展开全文
  • 二项队列Binomial Queue:(以下不只是简介,还包括了一些个人理解,如果您学习过程遇到什么麻烦,不妨先看看) 根据书上描述,似乎一种改良版。虽然左堆和斜堆每次操作都花费logN时间,且有效支持了...

     

        学习过程跟进黑皮书《数据结构与算法分析》,主要代码大致与树种例程相同,若有疏漏或错误,请务必提醒我,我会尽力修正。

     

    二项队列Binomial Queue:(以下不只是简介,还包括了一些个人理解,如果您学习过程遇到什么麻烦,不妨先看看)

        根据书上的描述,似乎是左式堆的一种改良版。虽然左式堆和斜堆每次操作都花费logN时间,且有效支持了插入、合并与最小值出堆,但其每次操作花费常数平均时间来支持插入。而在二项队列中。每次操作的最坏情况运行时间为logN,而插入操作平均花费常数时间。这算是在一定程度上优化了斜堆。

        其结构就如名字一样,是“二项”。我们可以将其简单理解为“上项”和“下项”(这只是为了方便理解罢了,实际运用中自然不存在这种称呼,但我总要找个名字给它,不然描述起来还挺费劲的)。实际的样子当您看到图片的时候就能明白,我为什么要那样称呼它们了。

        并且,二项队列的样子也特殊一点。它是一种被称之为“森林”的结构,形象的说,它包括了许多中不同高度的二叉树(但每一种高度的树只有一颗,一旦出现两颗同样高度,它们就会被立刻合并成新的高度,这也是特色之一)。并且,它也有最小堆的特性关键字的数值随高度递减,每一个根节点的值都比子树中任何一个节点的关键字小。

        如图,这便算是一个简单的二项队列结构。上面是一个数组,数组中存放有指针。而下面的则是许多的树(剥去数组,你看到的才是真正的二项队结构,数组只是从计算机中实现的一种方法罢了。并且,B3中的那颗树和我们实际实现的有些不同,具体的情况后面会写。但目前,权且当它就长这个样吧(或许这才是本该有的结构,但计算机不方便这样做,所以之后会有另外一个实现的样子))


        

    //-------------声明部分---------------//
    typedef struct BinNode* Position;//位置指针
    typedef struct BinNode* BinTree;//树指针
    typedef struct Collection* BinQueue;//队列指针
    #define MaxTrees 5 //数组的长度,也同时规定了二叉树的高度
    #define Capacity ((1<<MaxTrees)-1)//容量是2^0+2^1+......+2^(MAXTREES-1)
    BinQueue Initialize(void);//建立空队列
    BinTree CombineTrees(BinTree T1, BinTree T2);//合并高度相同的树
    BinQueue Merge(BinQueue H1, BinQueue H2);//合并两个队列
    int DeleteMin(BinQueue H);
    void Insert(int X, BinQueue H);
    int IsEmpty(BinQueue H);
    
    struct  BinNode //树节点
    { 
    	int Key;
    	Position LeftChild;
    	Position NextSibling;
    };
    struct Collection //森林
    {
    	int CurrentSize; //已容纳量
    	BinTree TheTrees[MaxTrees];//容纳二叉树的数组
    };
    //-------------声明部分---------------//

        因为书上没有说明一些变量的作用,所以我自己绕了一会,在这里顺便说明一下吧:

        CurrentSize:已容纳量。指的是整个队列的节点数。比方说上图中的的容纳量就是15(对应总共15个节点)。

        Capacity:队列容量。指的是一个二项队列结构最高能容纳的节点数。比方说上图的队列容量就是(B3——15)(也因为我画的不太好,所以B3看起来高度不像3,但会意一下就行,实在不行去找找其他大佬的图也行)。(但写法是一个等比数列求和结果,很明显,每个高度的节点数是等比增加的)

        LeftChild/NextSibling:连接指针。这个东西具体到后面看见实际的图片时,自然会懂。

     

    这幅图为实际做出的结构,以下说明的时候请经常对照以方便理解。高度相同的节点我已经尽量画在同一水平线了,也如您所见,B1没有节点,B3的高度确实是3(建立在B0处的节点高度设定为0的基础上)。

    关于LeftChild和NextSibling指针已经标出(取首字母表示)。

     

    建立队列Initialize:

    BinQueue Initialize(void)
    {
    	BinQueue H = new Collection;
    	for (int i = 0; i < MaxTrees; i++)
    		H->TheTrees[i] = NULL;
    	H->CurrentSize = 0;
    	return H;
    }

        没什么好说的,但因为书上没有,加上我当时不太明白几个参数的作用,所以绕了好一会,贴在这里以防万一。(至少如果不明白CurrentSize是什么,就没办法让它等于0了......)

     

    插入节点Insert:

    void Insert(int X, BinQueue H)
    {
    	BinQueue temp = initialize();
    	temp->CurrentSize = 1;
    	temp->TheTrees[0] = new BinNode;
    	temp->TheTrees[0]->Key = X;
    	temp->TheTrees[0]->LeftChild = NULL;
    	temp->TheTrees[0]->NextSibling = NULL;
    	Merge(H, temp);
    	delete temp;
    }

        从这个函数可以看出,所谓的插入节点,实际上是将新节点当作了一个只有B0结构的二项队列,然后将其合并。目前,我们只需要将Merge函数视作一个合并二项队列的函数即可,关于这个函数会在下面讲到。

     

    最小值出队DeleteMin:

    int DeleteMin(BinQueue H)
    {
    	int i, j;
    	int MinTree;
    	BinQueue DeleteQueue;
    	Position DeleteTree, OldRoot;
    	int MinItem;//ElementType
    
    	if (IsEmpty(H))
    		return NULL;
    
    	MinItem=INFINITY;
    	for (i = 0; i < MaxTrees; i++)
    	{
    		if (H->TheTrees[i] && H->TheTrees[i]->Key < MinItem)
    		{
    			MinItem = H->TheTrees[i]->Key;
    			MinTree = i;
    		}
    	}
    	DeleteTree = H->TheTrees[MinTree];
    	OldRoot = DeleteTree;
    	DeleteTree = DeleteTree->LeftChild;
    	delete OldRoot;
    
    	DeleteQueue = initialize();
    	DeleteQueue->CurrentSize = (1 << MinTree) - 1;
    	for (j = MinTree - 1; j >= 0; j--)
    	{
    		DeleteQueue->TheTrees[j] = DeleteTree;
    		DeleteTree = DeleteTree->NextSibling;
    		DeleteQueue->TheTrees[j]->NextSibling = NULL;
    	}
    	H->TheTrees[MinTree] = NULL;
    	H->CurrentSize -= (DeleteQueue->CurrentSize + 1);
    	Merge(H, DeleteQueue);
    	return MinItem;
    }
    

        函数本身不算难,但有些冗长。姑且做些说明,但自己写出来是最有效的理解方式。

        ①一系列将要用到的声明。其中MinItem是将要出堆的Key(因为我设定的Key是int类型),再将MinItem设定为无限大(Infinity)。

        ②遍历队列数组,选出队列中最小的关键字节点。用MinTree标记其对应的索引,MinItem拷贝其数值。

        ③将标记好的最小值节点拷贝到DeleteTree与OldRoot,再把DeleteTree指向其左儿子。删除最小值节点。

        ④将刚才拷贝的左儿子新建到另外一个队列里,设定好相关的数值,最后把两个队列合并。

        值得注意的是,for循环是将失去了根节点的堆重新整合到新队列中。这个操作看起来有些抽象,但实际上是可行的。不妨带入B3节点来试探一下,删去了根节点后,它被拆分成了B0,B1,B2三棵树进入新队列了。最开始的那幅图其实很好的说明了问题,那张图的B3有这明显的复制粘贴B2的痕迹,但事实就如描述一样,它们真的就是像复制粘贴一样的结构。所有你可以试着去拆分一下,Bk去掉根节点必然会变成B0,B1,B2......Bk-1颗树。

        以及另外一个注意点:

    	H->CurrentSize -= (DeleteQueue->CurrentSize + 1);
    

        其实不太必要在这个地方纠结太久,但以防万一还是说明一下。这行代码减去的数量将在Merge函数中补齐,先后的总节点数差距确实是 1 ,可以自行验证一下。如果缺乏这条函数,Merge将会导致CurrentSize与实际不符。(之所以减去那个量,是因为Merge会补回DeleteQueue->CurrentSize的数量,和这段语句正好相差 1 )

     

    合并队列Merge:

    BinTree CombineTrees(BinTree T1,BinTree T2)
    {
    	if (T1->Key > T2->Key)
    		return CombineTrees(T2, T1);
    	T2->NextSibling = T1->LeftChild;
    	T1->LeftChild = T2;
    	return T1;
    }
    
    BinQueue Merge(BinQueue H1,BinQueue H2)
    {
    	BinTree T1, T2, Carry = NULL;
    	int i,j;
    	if (H1->CurrentSize + H2->CurrentSize > Capacity)
    		exit;
    	H1->CurrentSize += H2->CurrentSize;
    	for (i = 0, j = 1; j <= H1->CurrentSize; i++, j *= 2)
    	{
    		T1 = H1->TheTrees[i]; T2 = H2->TheTrees[i];
    		switch(!!T1+2*!!T2+4*!!Carry)
    		{
    			case 0://No tree
    			case 1://only h1
    				break;
    			case 2://only h2
    				H1->TheTrees[i] = T2;
    				H2->TheTrees[i] = NULL;
    				break;
    			case 4://only carry
    				H1->TheTrees[i] = Carry;
    				Carry = NULL;
    				break;
    			case 3://h1 and h2
    				Carry = CombineTrees(T1, T2);
    				break;
    			case 5://h1 and carry
    				Carry = CombineTrees(T1,Carry);
    				H1->TheTrees[i] = NULL;
    				break;
    			case 6://h2 and carry
    				Carry = CombineTrees(T2,Carry);
    				H2->TheTrees[i] = NULL;
    				break;
    			case 7://h1 and h2 and carry
    				H1->TheTrees[i] = Carry;
    				Carry = CombineTrees(T1,T2);
    				H2->TheTrees[i] = NULL;
    				break;
    		}
    	}
    	return H1;
    }
    

        最后是关键性的函数,Merge。这个例程还需要用到CombineTrees函数,用于合并高度相同的树。

        函数本身并不是很复杂,用了一个switch来判断情况,这个方式相当有趣,是很值得学习的一种想法。(!!符号似乎是用来判断存在性的(我不太清楚这样描述对不对,所有用“似乎”),若值存在且非0,则返回1,否则返回0)。

        以及比较有趣的是for循环的判断条件 j<=H1->CurrentSize 和 j*=2

        看起来有些抽象,解释起来也是。

        现在的H1->CurrentSize已经是合并结束后的总节点数量了,而这个数量直接关系到for循环需要抵达哪一个高度的数组格。(比如说,我的数组最高能到B20,但现在根本没有那么多树需要存放,最高的树高度只到B5,那如果全都扫一遍,岂不是浪费了很多时间?)

        所有才有 j*=2这个条件来制约。如您所见,每个高度的节点数实际上是固定的 2^Bk(2的Bk次方,k指高度,如B0,B1等)。这就涉及到了一些数学关系,所有我就不写这了。只需要捋一捋,我想很快就会发现这神奇的操作(如果最高到B5,那这个for循环进行4次之后,它的 j 就会超出范围导致for循环终止)。

        流程其实没必要细讲了,函数写的很清楚了,注释也有,笔记的目的已经达成了,那就到这吧。

    展开全文
  • 次函数表达式右边通常为次三项式次函数三种表达式一般式:y=ax2+bx+c(a,b,c为常数,a≠0)顶点式:y=a(x-h)2+k(抛物线顶点P(h,k))注:其中h=,k=交点式:y=a(x-x1;)(x-x2;)(x1与x2为抛物线...

    fc3cfaa74a5837d55b6a19a006668756.png

    一、定义与定义表达式

    一般地,自变量x和因变量y之间存在如下关系:y=ax2+bx+c(a,b,c为常数,a≠0)则称y为x的二次函数。二次函数表达式的右边通常为二次三项式。

    二、二次函数的三种表达式

    一般式:y=ax2+bx+c(a,b,c为常数,a≠0)

    顶点式:y=a(x-h)2+k(抛物线的顶点P(h,k))

    注:其中h=,k=

    交点式:y=a(x-x1;)(x-x2;)(x1与x2为抛物线与x轴的交点横坐标)

    三、二次函数的图像

    在平面直角坐标系中作出二次函数y=x2的图像,可以看出,二次函数的图像是一条抛物线。

    四、抛物线的性质

    1. 抛物线是轴对称图形。对称轴的表达式为x=

    对称轴与抛物线唯一的交点为抛物线的顶点。特别地,当b=0时,抛物线的对称轴是y轴(即直线x=0)

    2. 二次项系数a决定抛物线的开口方向和大小

    当a>0时,抛物线开口向上;当a<0时,抛物线开口向下。|a|越大,抛物线的开口越小。|a|越小,抛物线的开口越大。

    3. a具有平移不变性。当抛物线在坐标系内平移时,a不发生改变。

    4. 一次项系数b和二次项系数a共同决定对称轴的位置(左同右异)

    当抛物线对称轴在y轴左侧时,a与b同号;当抛物线对称轴在y轴右侧时,a与b异号。

    5. 常数项c决定抛物线与y轴交点

    抛物线与y轴交于(0,c)

    6. 抛物线与x轴交点个数

    Δ=b2-4ac>0时,抛物线与x轴有2个交点。

    Δ=b2-4ac=0时,抛物线与x轴有1个交点。

    Δ=b2-4ac<0时,抛物线与x轴没有交点。

    五、二次函数与一元二次方程的关系

    1. 二次函数y=ax2+bx+c,当y=0时,二次函数变为关于x的一元二次方程,即a x2+bx+c=0。此时,函数图像与x轴有无交点即方程有无实数根。函数与x轴交点的横坐标即为方程的根。

    2. 二次函数y=ax²+bx+c,当y=n时,二次函数变为关于x的一元二次方程,即ax²+bx+c=n。此时,函数图象与y=n有无交点即方程有无实数根。

    3. 二次函数y=ax²+bx+c,一次函数y=kx+b,则ax²+bx+c=kx+b的解即为二次函数与一次函数交点的横坐标

    六、二次函数的增减性

    抛物线y=ax²+bx+c(a≠0),若a>0,当x≤时,y随x的增大而减小;当x≥时,y随x的增大而增大。若a<0,当x≤时,y随x的增大而增大;当x≥时,y随x的增大而减小。

    七、用待定系数法求二次函数的解析式

    1. 当题给条件为已知图象经过三个已知点或已知x、y的三对对应值时,可设解析式为一般形式:y=ax²+bx+c(a≠0).

    2. 当题给条件为已知图象的顶点坐标或对称轴时,可设解析式为顶点式:y=a(x-h)²+k(a≠0).

    3. 当题给条件为已知图象与x轴的两个交点坐标时,可设解析式为两根式:y=a(x-x1)(x-x2)(a≠0).

    八、天津中考常见考点

    判断下列各式的正负(选择12题):abc(判断a、b、c各自符号)、a+b+c、4a-2b+c(特殊点的符号)、2a+b、2a-b(利用对称轴的位置判断)、b²-4ac(利用图象与x轴交点个数判断)、a的取值范围(通过图象开口大小范围判断)

    求抛物线解析式(25题第(1)问):按照题目条件求解析式,一次性百分百做对,做完立即检查。

    通过平移确定新抛物线解析式:将原抛物线解析式化成顶点式,根据“左加右减,上加下减”求得新抛物线解析式

    f09a28590e3acbf39aff1dc1a217e80a.png

    00caefda7f6e7900ab887b3a40733592.gif

    展开全文
  • 于是我们考虑问题是:齐次方程组:是否存在非零解,以及存在条件通解结构与性质解法非齐次方程组:是否有解,以及有解条件是什么有多少解以及对应解数量条件是什么多解结构与性质解法行列式二,三阶行列...

    6661f4df57bc5176ee47e4190aec4433.png

    实际意义

    求线性方程组

    线性方程组一般有 m 个常数项,n 个未知数,m * n 个系数。若常数项全为 0 ,则为齐次线性方程组;若未知数全为 0 ,则称为零解。

    于是我们考虑的问题是:

    齐次方程组:

    1. 是否存在非零解,以及存在的条件
    2. 通解的结构与性质
    3. 解法

    非齐次方程组:

    1. 是否有解,以及有解的条件是什么
    2. 有多少解以及对应解数量的条件是什么
    3. 多解的结构与性质
    4. 解法

    行列式

    二,三阶行列式

    行列式最初的作用就是求解线性方程组!

    例如:最简单的二元线性方程组

    可以归纳出答案是由方程组的四个系数以及常数决定的。于是记四个系数为行列式,并规定行列式的值就是上述式子的分母:

    于是有了这么一个行列式之后,我们就可以得到:

    同理,可以拓展到三元线性方程组,定义三阶行列式。这里还记得一点的是,对于二阶,三阶行列式,我们可以使用对角线法则来方便计算,一句话描述对角线法则就是:主对角线上的元素乘积减去副对角线上的

    68cedcb3efc72f8accd822c2acf6c468.png

    n 阶行列式

    刚才提到了对角线法则,务必要记住,只有二阶和三阶的行列式能使用这个法则!既然如此,我们就需要定义一个正式的值计算公式。

    由刚才二,三阶行列式的实践,我们可以推广以下规律:

    1. n 阶行列式的值是 n! 个不同项的代数和,其中每项都是不同行不同列的 n 个元素的乘积
    2. 每项的正负号取决于其 n 个元素的下标排列,即将元素按照行顺序排列之后,列排列的逆序数。若逆序数为偶数,则该项符号为正,反之为负

    于是可以推出 n 阶行列式的值为:

    行列式的性质

    首先要明确一点,行列式获得的是一个。也就表示,如果我们对行列式的操作,不会改变这个值,那么这个操作就是合法的,大家可以根据这一点对这些性质进行证明。

    1. 行列式 = 转置行列式
    2. 交换行列式中的两行(列),行列式的符号取反
    3. 若行列式中某行(列)所有元素都有一个公因子 k ,则可以把公因子提到行列式记号之外
    4. 若行列式中某行(列)各元素都是两数之和,则可以把该行列式分解为两个行列式之和
    5. 将行列式中的某行(列)中所有元素乘以 k 后,加到另一行(列)上,行列式的值不变

    这些性质的提出,目的无他,就是为了行列式好计算。如果直接按照定义计算 n 阶行列式,那么运算次数为 (n - 1) * n! 次,计算次数有点太多了,所以需要其他手段来化简运算。利用性质,可以把普通的行列式转化为特殊形式(例如上三角,下三角这种有规律的行列式)来简化运算。

    行列式按行(列)展开

    还是从二阶,三阶行列式入手,如果按照定义写出三阶行列式的计算公式,你会发现:

    能把三阶行列式简化到了二阶行列式的计算!这就是行列式的展开:

    在 n 阶行列式中,把元素

    所在的行列划去之后,留下的 n - 1 阶行列式叫做元素
    余子式,记
    。记
    为元素
    代数余子式

    于是我们就获得了新的行列式计算公式:

    如果你细究一下会发现,展开需要的计算和定义是一样的,并没有什么差别。但是如果一行(列)含有较多零时,展开定理能减少运算量,直接把那一行(列)展开即可。

    克拉默法则

    如果你善于发现,你会发现行列式一直是个正方形,没错,这就是行列式的特点,所以它只能用于 m = n 情况的线性方程组,对于这一类方程,存在克拉默法则来计算解是否唯一的问题:

    若线性方程组系数行列式不等于零,则有唯一解,其中解的表示为

    矩阵及其运算

    矩阵的提出与概念

    行列式已经能解决一部分的线性方程组问题,但是还不够,我们已经知道线性方程组的解取决于它的系数a 以及常数项 b :

    将线性方程组的系数与常数项按原位置排列就可以得到:

    于是线性方程组就可以由这张表唯一确定,则对于线性方程组的研究就可以转化到对这张表的研究,这张表就是矩阵!

    由 m*n个数排成的 m 行 n 列的数表称为m*n 矩阵,其中的数称为元素。如果元素都是实数,则是实矩阵;含有复数则是复矩阵。如果 m = n,则是方阵。

    其中若方阵的主对角线元素都为 1 ,其余为 0 ,则称为单位矩阵,记作 E 或者 I。

    这里还要区分一下矩阵和行列式两个概念:

    1. 行列式是值,矩阵是表达形式,也就是说,矩阵不可以计算(这隐含着,行列式的性质到了矩阵这都不管用了)
    2. 行列式的行数必等于列数,而矩阵不需要

    同时,需要知道的是,除了线性方程组,矩阵还广泛运用在线性变换上:线性变换也能由一个系数矩阵来唯一确定

    矩阵的运算

    首先是线性运算:加法与数乘。要注意的是矩阵的加法是两个行列数相等的同型矩阵的对应元素相加;而矩阵的数乘是要将常数乘上矩阵上的各元素,而不是行列式一样,只用乘到某行或者某列。

    矩阵的转置,将矩阵的行列元素互换:

    转置有一条运算规律需要留意:

    对于方阵,由于行列数相等,我们定义一种特殊运算叫做方阵的行列式,即将矩阵转化为了行列式:由 n 阶方阵元素按照原位置所构成的行列式。也有两条运算规律需要留意:

    1. det(AB) = detA * detB = det(BA)
    2. det(A + B) ≠ detA + detB

    除此之外,对于方阵 A ,由其行列式各个元素对应的代数余子式所构成的方阵,称为 A 的伴随矩阵,记作 A* 。这里不是说随便构成的就是伴随矩阵,而是原方阵的转置对应的各元素排列之后的矩阵才是:

    为什么要强调这个排列呢,因为这个排列下能满足性质:

    矩阵乘法:m*s 阶的矩阵 A 及 s*n 阶的矩阵 B 的乘积为 m*n 阶的矩阵 C ,其中 C 的元素为:

    前提是矩阵 A 的列数 = B 的行数,即 (m*s) * (s*n) = m*n ,由此可以推出,幂运算在矩阵中,只有方阵才能实现。

    逆矩阵 - 矩阵的除法

    逆矩阵:对于 n 阶方阵 A, 若有 n 阶方阵 B ,使得 AB = BA = E ,那么 A 是可逆的,B 称为 A 的逆矩阵,记为

    。这里要注意的是,逆矩阵只针对方阵,简单点理解的话,因为单位矩阵是方阵就好了。

    为什么要把逆矩阵单列出来呢?因为逆矩阵就是解决刚才提到的矩阵应用的关键所在!

    1. 线性方程组求解:

    1. 线性变化的逆变换:

    但是逆矩阵引出了两个问题:什么样的方阵是可逆的?怎么求一个方阵的逆矩阵?

    第一个问题的答案是 detA ≠ 0 ,理由很简单:

    同时这个理由还给了我们一种求逆矩阵的方法:伴随矩阵法,但是由于求伴随矩阵还是非常复杂,所以不是很提倡这种方法。除了这以外,还可以使用原始的待定系数法来求,这种肯定也是不推荐了。

    矩阵的初等变换

    由于之前的两种方法都不够高效,我们需要一种全新的思路,也就是利用矩阵的初等变换。

    对矩阵进行的以下三种变换称为初等变换

    1. 对调两行/列
    2. 以数 k ≠ 0 乘以某一行/列的所有元素
    3. 将某一行/列的所有元素的 k 倍加到另一行/列的对应元素上去

    联想到行列式,你会发现这三种变换在行列式的性质中都是可以找到的,很容易知道方阵进行这些变换之后的行列式变化,再联想到方阵可逆的充要条件就是方阵的行列式不为 0 ,你大概就能知道为啥会突然冒出来这么三种变换操作。而且从直观上来看,每一种初等变换都是变得过去,就能变得回来,专业点说就是可逆的。

    对单位矩阵 E 进行一次初等变换得到的矩阵称为初等矩阵。而对矩阵进行初等变换等于矩阵乘上一个初等矩阵:

    1. 对矩阵进行一次初等行变换,等于左乘一个相应的初等方阵 ⇒ 行变换,左乘
    2. 对矩阵进行一次初等列变换,等于右乘一个相应的初等方阵 ⇒ 列变换,右乘

    这样的操作还保证了初等变换前后的行列式不变(因为 det(AB) = detA * detB)。所以如果方阵 A 可逆,就代表了其行列式不为 0 ,那么 A 就能表示为若干个初等方阵的乘积,因为初等方阵的行列式除了不等于 0 ,其他的都能做到。

    这里再提一个等价的概念:如果矩阵 A 经过有限次初等变换之后能够得到矩阵 B ,换个表达就是,存在可逆方阵 P 和 Q 使得 PAQ = B ,那么我们就称矩阵 A 与 矩阵 B 之间是等价的。

    所以方阵 A 可逆的另一个充要条件的标准表述就是,方阵 A 与单位矩阵等价,即:

    利用这个,我们就获得了最常用的求逆矩阵的方法,初等变换法:

    所以我们构造 (A|E) 矩阵,然后将 A 经过初等行变换化为单位矩阵 E ,那么右侧自然就是 A 的逆矩阵。如果 A 不可逆,会发现怎么也变不成 E ,因为其行列式是 0 。要注意的是,一定只能有初等行变换,不能夹杂着列变换!

    会求逆矩阵之后,矩阵的应用就变得唾手可得了。

    利用矩阵求解线性方程组

    如果熟悉线性方程组的消元法,会发现矩阵的初等行变换就是消元法中的操作:

    1. 互换矩阵的两行 = 互换两个方程
    2. 数乘某行 = 数乘某个方程
    3. 某行的 k 倍加到另一行 = 某方程的 k 倍加到另一方程

    于是利用矩阵的初等行变换,我们能将线性方程组对应的矩阵化简为行最简形,注意只能用初等行变换

    9de749cc3492cf74a4b15cb05aa09694.png

    该矩阵为线性方程组消元之后的增广矩阵 B,而除去虚线之后的矩阵是消元之后的系数矩阵 A。

    这里为了方便陈述,再引入一个概念,矩阵的秩:在 m*n 的矩阵 A 中,任取 k 行和 k 列交叉的

    个元素,按原次序所组成的 k 阶行列式,称为 A 的一个 k 阶子式,记作
    。若该矩阵某个 r 阶子式
    ≠ 0 且所有的 r + 1 阶子式
    = 0 ,那么 r 称为矩阵的秩,记 rankA = r 或 r(A) = r 。

    可以明显看出,如果一个 n 阶方阵 A 的秩如果是 n 的话,即满秩,那么 detA ≠ 0 ,那么 A 可逆。而且初等变换不会改变矩阵的秩,因为那些操作对于行列式,不能把非零值变成零,也不能把零值变成非零值。

    在行最简形中,我们可以明显看出,增广矩阵 B 的秩 ≤ r + 1 ,系数矩阵 A 的秩 ≤ r ,于是有下面几种情况:

    1. ≠ 0 ⇒ rankB = r < rankA =r + 1 ⇒ 0 + 0 + ... + 0 =
      ⇒ 方程组无解
    2. = 0 ⇒ rankB = rankA ⇒ 方程组有解
      1. rankA = rankB = n ⇒ 方程组有唯一解 ⇒ 解
      2. rankA = rankB = r < n ⇒ 方程组有无穷大解
        称为自由未知量

    c8d90b9667fca2d6b56ce501bfadc82a.png

    对于齐次方程,由于 d 都为 0 ,所以可以直接考虑系数矩阵,若 rankB < n 则有无穷多组解,反之只有零解。

    展开全文
  • 次函数的三种表达式:...一、一般式:一般式的表达式y=ax2+bx+c(a≠0),a、b、c分别是二次项、一次项、常数项的系数,a、b、c分别有什么用途呢?1、a的符号确定了抛物线的开口方向,a>0时,抛物线的开口向上...
  • 代表n项观察或子采样中某事物(x +)成功出现次数的二项式数据。 这些数据生成方式可以模拟在实践中应该观察到内容,但可以避免其他形式实验错误。 基于对104个Δ测量分析,我们表明平均Δ()与(σx•μ-...
  • 3. 在8086中,逻辑地址、偏移地址、物理地址分别指的是什么?具体说明。 4. 什么是硬件中断和软件中断?在PC机中两者处理过程有什么不同? 六、综合应用题(每题10分,共20 分) 现有16K×1位动态...
  • 基础指数级数公式展开来源

    千次阅读 2011-06-13 08:47:00
    下面就是重要一步,对上面等式两边分别取i幂次方,而这个i很大很大值,这样上面式子可以变形为:(a^w)^i=(1+k*w)^i,到这里为止,也还是正常,精彩的是这里可以应用newton的二项式公式了,
  • 如果时变项是通过函数定义,则这个函数在导数函数需要时候被调用。 本例中用到微分方程是带有一个正弦驱动项阻尼波动(Damped Wave)方程。 y’’(t)- beta * y’(t) omega^2 * y(t)= A* sin ...
  •  本题实际上是求数列{an}前n项绝对值之和,由绝对值意义,应首先分清这个数列哪些项是,哪些项是非负,由已知数列{an}是首项为负数递增数列,因此应先求出这个数列从首项起共有哪些项是负数,然后再...
  • 你必须知道495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    1.4 新64位机上64位类型是什么? 指针声明 1.5 这样声明有什么问题?char*p1,p2;我在使用p2时候报错了。 1.6 我想声明一个指针,并为它分配一些空间,但却不行。这样代码有什么问题?char*p;*p=...
  • PID算法运用

    2015-06-14 20:23:54
    、然后要知道PID算法具体分两种:一种位置式的 ,一种增量式的。在小车里一般用增量式,为什么呢?位置式PID的输出与过去的所有状态有关,计算时要对e(每一次的控制误差)进行累加,这个计算量非常大,而明显...
  • 1.4 新64位机上64位类型是什么? 3 指针声明 3 1.5 这样声明有什么问题?char *p1, p2; 我在使用p2时候报错了。 3 1.6 我想声明一个指针,并为它分配一些空间,但却不行。这样代码有什么问题?...
  • 《你必须知道495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    1.4 新64位机上64位类型是什么? 3 指针声明 3 1.5 这样声明有什么问题?char *p1, p2; 我在使用p2时候报错了。 3 1.6 我想声明一个指针,并为它分配一些空间,但却不行。这样代码有什么问题?...
  • 你必须知道495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    1.2 64 位机上64 位类型是什么? . . . . . . . . . . . . . . . . 1 1.3 怎样定义和声明全局变量和函数最好? . . . . . . . . . . . . . . . 2 1.4 extern 在函数声明中是什么意思? . . . . . . . . . . . ...
  • 因为在这里我们使用的是的二项分布(因变量),我们需要选择一个对于这个分布最佳连结函数。 它就是Logit函数。 在上述方程中,通过观测样本极大似然估计值来选择参数, 而不是最小化平方和误差...
  • 有限元法基本方程中每一项的意义是什么 P14 答:Q——整个结构节点载荷列阵(外载荷、约束力);整个结构节点位移列阵;结构整体刚度矩阵,又称总刚度矩阵。 8. 位移边界条件和载荷边界条件意义是什么 ...
  • o 2.2 64 位机上 64 位类型是什么? o 2.3 怎样定义和声明全局变量和函数最好? o 2.4 extern 在函数声明中是什么意思? o 2.5 关键字 auto 到底有什么用途? o 2.6 我似乎不能成功定义一个链表。我试过 ...
  • 软件工程教程

    热门讨论 2012-07-06 23:10:29
    问:开发这个软件目标是什么? 答: 提高用户对音乐学习和娱乐 参与创作音乐 项目背景--钢琴练奏师 问:为什么传统音乐程序不好? 答: 传统音乐程序功能单一,容易令人感到枯燥无味,没有吸引力; 传统音乐...
  • 实现了一个基本的二维图像库 io 提供了对I/O原语基本接口 log 它一个简单记录包,提供最基本日志功能 math 提供了一些基本常量和数学函数 mine 实现了部分MIME规范 net 提供了一个对UNIX...
  • windows 程序设计

    2011-07-24 21:16:30
    在Windows NT和Windows 98中,多任务优先权式的,而且程序自身可分割成近乎同时执行的多个执行绪。 操作系统不对内存进行管理便无法实现多任务。当新程序启动、旧程序终止时,内存会出现碎裂空间。系统必须能够将...

空空如也

空空如也

1 2 3
收藏数 47
精华内容 18
关键字:

二项式的常数项是什么