P3-无序列表-有序列表-表现编写位置-选择器-声明块-伪类选择器-a标签的伪类选择器-属性选择器-伪元素

列表

list:主要用来表示多个并列关系的内容

无序列表

使用ul标签来创建一个无序列表

<ul>
	<li></li>           
	<li></li>   
<ul>
有序列表

(项目符号用的是1234):使用ol标签来创建一个有序列表

<ol>
   <li></li>           
   <li></li>   
<ol>

注意:

  • 两种列表的表项都使用的是li标签
  • 列表之间可以互相嵌套,可以在一个有序列表中放一个无序列表,也可以在无序列表中放一个有序列表。
  • ul主要用来做导航条
  • 真正这种一级二级的效果比较像下拉菜单效果
定义列表

主要用于对一些内容下定义

<dl>
    <dt></dt>
    <dd></dd>
</dl>

解释:

  • dl:用来标识列表是定义列表
  • dt:用来标识定义项
  • dd:用来描述定义项
    案例:
    在这里插入图片描述
传统的导航条

案例:

<!-- #表示返回顶部/占位符(具体填写点击后跳转的链接)-->
<ul>
    <li><a href="#">主页</a></li>
    <li><a href="#">关于</a></li>
    <li><a href="#">我的</a></li>
    <li><a href="#">联系</a></li>
</ul>

CSS(Cascading Style Sheets)层叠样式表

概述
  • CSS用于设置页面中元素的样式,属于 ”结构表现行为”中的表现。
  • 所谓的表就是可以给网页中的多个模块设计样式
  • 用来处理页面的表现
  • 网页中所有的外在显示效果都由CSS来控制
表现的编写位置:
  • 第一种 内联样式:可将css代码编写到标签的style属性中,style属性写在html标签中。
    将样式直接编写到style属性中这样会导致结构和表现耦合,不方便代码复用,并且不方便后期的维护,所以在开发中永远不要使用内联样式。
<p style='color: red;font-size: 30px;'>落霞与孤鹜齐飞,秋水共长天一色</p>
  • 第二种 内部样式表 :可将css代码编写到一个style标签
    将样式编写在style标签中,然后通过CSS选择器选中指定的元素为其设置样式,将HTML和CSS代码分离开,使CSS样式可以复用,并且方便后期的维护。缺点(只在当前页面内有效,别的页面无效)
    style标签里面采用的是css语言,而外面采用的使html
    style标签写在head标签中。
<style>
    p{
        color: red;
        font-size: 60px;
        background-color: aquamarine;
    }
/*    选中p元素,大括号中的样式对选中元素进行设置*/
    </style>
<p>落霞与孤鹜齐飞,秋水共长天一色</p>
  • 第三种 外部样式表 :可以将css代码编写到一个外部文件中,然后通过link标签引入
    标签link需要写入head中。
    将CSS写在外部的样式表中,使结构和表现完全分离,可以在不同的页面中对样式表进行复用,方便后期的维护。将样式表写在外部文件中,可以充分的利用到浏览器的缓存机制,进而加快页面的加载速度,提高用户体验。
    在这里插入图片描述
    rel属性:必须有的,规定当前文档与被链接文档/资源之间的关系。属性值stylesheet意思是:要导入的样式表的URL。

CSS基本语法

选择器 和 声明块
  • 选择器:通过选择器可以选中页面中的指定元素
  • 声明块:声明块整体由一对大括号包裹,里面由一个一个的声明组成
    声明是一个一个的名值对结构,属性名和属性值用:(冒号)连接,用;(分号)结尾
    声明用来为选择器所指定的元素来设置样式。
    声明块
选择器
选择器名格式说明举例
元素选择器标签名{}根据标签名来选中指定的元素p{} span{} div{}
id选择器#id{}根据元素的id属性值选中一个元素#box #p1
类选择器.类名{}根据元素的class属性选中元素.box .p1
并集选择器选择器1,选择器2,…选择器n根据元素的id属性值选中一个元素p1,p2…pn
统配选择器*{}选中页面中的所有元素* {}
交集选择器选择器1选择器2…选择器n选中同时符合多个选择器的元素div.box{} 元素选择器+类选择器
.div{}相当于*.div{}
div#box{}不建议这么创建规则 元素选择器+id选择器
后代元素选择器祖先 后代选中指定元素的后代元素p span{} div p {}
子元素选择器父元素 > 子元素选中父元素的指定子元素div > p{} p > span{}
下一个兄弟元素兄 + 弟选中指定的元素的兄弟元素选择弟元素,且弟在兄紧挨着之后,否则什么也不选中
后面所有兄弟元素兄 ~ 弟选中指定的元素的兄弟元素选择弟元素,不管弟元素是否紧挨着兄,都选中

注意:

  • css中,逗号(,)一般都表示或者的意思
  • 元素除了可以添加id属性外,还可以添加class属性

class属性

  • 作用:为元素进行分类(持有相同class属性的元素属于同一类元素)
  • 设置方式:与id属性基本一致,不同的是class属性可以重复使用
  • class可以和id用同样的名字,但是id本身不能有重复
  • id只能有一个,但是可以同时为一个元素设置多个class
元素之间的关系

元素之间的关系是为了选中元素。

元素名称含义
父元素直接包含子元素的元素
子元素直接被父元素包含的元素
祖先元素直接或间接包含后代元素的元素、父元素也属于祖先元素
后代元素直接或间接被祖先元素包含的元素、子元素也属于后代元素
兄弟元素拥有相同父元素的元素

元素之前关系

伪类选择器
  • 都是以:(冒号)开头
  • 伪类表示元素的一些特殊状态或位置

伪类选择器表

伪类选择器名说明案例
:first-child第一个子元素
在所有的子元素中查找
div p:first-child{}
找的是标签div下的所有元素,第一个元素是p标签的 选中
:first-of-type同类型的第一个子元素div p:first-of-type{}
要选中div下的所有p元素的第一个
:last-child最后一个子元素
在所有子元素中查找
div p:last-child{}
要找的是标签div下所有的元素,最后一个元素是p标签的 选中
:last-of-type同类型的最后一个子元素div p:last-of-type{}
要选中div下的所有p元素的最后一个
:nth-child(n)第n个子元素
(在所有子元素中查找)
参数:odd(奇数)even(偶数)
p:nth-child(even)
选中同一级别的 所有元素中 偶数位置的p元素
:nth-of-type(n)同类型的第n个子元素p:nth-of-child(2)
选中同一级别的 p标签的第二个
:only-child唯一的子元素
匹配属于父元素中唯一子元素的元素
p:only-child{}
选中父元素的子元素只有一个元素且为p的
:only-of-type同类型中唯一的子元素
匹配属于同类型中唯一同级元素
p:only-of-type{}
选中父元素的子元素中p元素的个数是一个的
:empty空元素
什么都都没有才是空元素,含有空格则不为空元素
div:empty{}
选中是空的div元素
:not除了
表示否定伪类
p:not(.p1){}
选中所有p元素,除了设置class属性为p1元素

first-child:
first-child
first-of-type
first-of-type
nth-child(n)
nth-child(n)
nth-of-type(n)
nth-of-type
only-child
only-child
only-of-type
only-of-type
empty
empty
not
not

a标签—超链接的伪类
伪类名说明
:link正常的链接(带有href的a标签)
主要用来设置没有访问的链接的形式
:visited访问过的链接
由于隐私原因,visited这个伪类只能修改字体的颜色,其余样式都不能修改
:hover鼠标移入的状态
不仅仅适用于超链接、其他元素也可以.鼠标移上去改变样式
:active鼠标点击的状态
不仅仅适用于超链接、其他元素也可以使用
:link
link
:visited
visited
:hover
hover
:active
active
属性选择器

属性选择器 根据元素的属性来选中元素

属性选择器名说明
[属性名]获取含有指定属性的元素
如果前面没有指定元素,则认为从全局中的所有元素查找
[属性名 = X]表示选中属性名=X的项
区分大小写
[属性名 = X i]表示选中属性名 = X的项 且忽略大小写。i表示not (意思是忽略大小写)
[属性名 ^=X]表示选中属性名 且 属性值以X开头
[属性名 ^=X i]表示选中属性名 且 属性值以X开头 且忽略大小写
[属性名$ = X]表示选中属性名 且属性值以X结尾
[属性名$ = X i]表示选中属性名 且属性值以X结尾 忽略大小写
[属性名 *= X]表示选中属性名 且属性值包含X
[属性名 *= X i]表示选中属性名 且属性值包含X 忽略大小写
[属性名]
属性名
[属性名 = 属性值]
[属性名 = 属性值]
[属性名 = 属性值 i]
[属性名 = 属性值 i]
[属性值 ^ = 属性值]
[属性名^=属性值]
[属性名 ^=属性值 i]
[属性名 ^= 属性值 i]
属性名 $ =属性值,属性名 $=属性值 i
[属性名 $=属性值]
[属性名 *= 属性值]
[属性名 *= 属性值]
伪元素

伪元素主要表示一些特殊的元素

伪元素说明
::before
(元素开头的位置)
表示开始标签和文本之间的位置
使用content属性添加内容
::after
(元素结尾的位置)
表示文本和结束标签之间的位置
使用content属性添加内容
::first-letter选中元素的第一个字母或汉字
::first-line选中元素的第一行
::selection表示选中的内容
::before
::before
::after
::after
::first-letter
::first-letter
::first-line
first-line
::selection
::selection
注意:
  • 采用两个冒号和一个冒号都可以,但是在brackets软件中,两个冒号可以出现属性提示
  • before和after是通过css中加的,不是html,所以在网页中不能通过鼠标将其选中
  • 如果想要在元素开头或者元素结尾处添加内容,需要使用content属性在这些位置添加内容
  • before和after的具体位置是:
    before-after

游戏 关于选择器的

游戏链接
游戏结果
game1
game2
game3

<think> 我们已经在之前的讨论中修正了外层循环少一次的问题。现在,用户要求对乘法结果进行消除同类项的优化。 同类项是指具有相同指数(expn)的项,我们需要将它们的系数(coef)相加,合并为一项。 当前Mul函数执行后,head3所指向的链表是head1和head2两个多项式相乘的结果,但是结果中可能存在多个相同指数的节点。 我们可以考虑在乘法完成后,对结果链表进行合并同类项的操作。 合并同类项的一般步骤: 1. 对链表按指数(expn)进行排(升或降),这样相同指数的节点会相邻。 2. 遍历排后的链表,将相邻的相同指数的节点合并(系数相加),并删除多余的节点。 但是,排会增加时间复杂度。另一种方法是在构建结果链表时,每次插入新节点时检查是否已有相同指数的节点,若有则合并,否则插入。 但是,由于我们是在构建链表的过程中,节点是无序的,所以每次插入都需要遍历整个结果链表来查找相同指数,时间复杂度为O(n),整体为O(n^2)。 考虑到多项式的项数可能较多,我们可以在乘法完成后对整个链表进行排,然后遍历合并,这样时间复杂度可能更优(排O(n log n) + 合并O(n))。 然而,题目要求我们直接在Mul函数中实现,所以我们可以有两种选择: 方案1:在乘法完成后,对结果链表进行排,然后合并同类项。 方案2:在每次插入新节点时,维护结果链表有序,并检查合并。这样插入时的时间复杂度为O(n),总时间复杂度为O(n^2)(n为结果链表的长度)。 由于多项式乘法本身的时间复杂度已经是O(m*n)(m和n分别是两个多项式的项数),而合并同类项如果采用方案2(即插入时保持有序并合并),则整个乘法过程的时间复杂度将变为O(m*n*k),其中k为当前结果链表的长度(在最坏情况下,k会增长到m*n,所以总时间复杂度为O((m*n)^2)),这在m和n较大时是不可接受的。 因此,我们可以考虑在乘法完成后进行排和合并,这样总的时间复杂度为O(m*n + (m*n)*log(m*n) + (m*n)),即O((m*n)*log(m*n))。 具体步骤: 步骤1:执行当前的乘法操作,构建一个无序的结果链表(head3)。 步骤2:对结果链表按指数进行排(可以使用归并排,因为链表排中归并排是稳定的O(n log n))。 步骤3:遍历排后的链表,合并同类项(相同指数的节点合并,系数相加,并删除重复节点)。 由于题目要求修改Mul函数,我们将这些操作集成到Mul函数中。 注意:我们假设多项式链表中每个节点定义如下(用户没有给出,我们假设): typedef struct node { float coef; // 系数 int expn; // 指数 struct node* next; } NODE; 我们首先完成乘法(修正后的版本),然后编写一个链表排函数(归并排)和一个合并有序链表中同类项的函数。 由于题目要求不能增加额外函数(或者可以增加?),但为了清晰,我们可以在Mul函数内部调用排和合并函数。但考虑到C语言不允许嵌套函数,我们可以将排和合并写成外部函数,或者写在Mul函数内部通过循环实现排(但归并排递归实现需要额外函数)。 这里我们选择在Mul函数内部实现一个归并排(非递归,避免额外函数)?但非递归归并排对链表的实现也是需要多个函数的,所以我们还是写一个辅助函数。 考虑到题目可能要求所有操作在Mul函数内完成,我们可以将排和合并操作写在Mul函数内,但这样会使得Mul函数很长。另一种思路是:在合并同类项之前,我们可以不对整个链表排,而是采用一种更简单的方法:遍历链表,将相同指数的节点合并。但是,如果不排,我们需要对每个节点遍历整个链表来合并同类项,时间复杂度为O((m*n)^2),在项数多时效率低。 因此,我们决定采用归并排链表,然后合并同类项。 计划: 1. 完成乘法(修正后的循环重置问题)。 2. 对结果链表(head3->next开始的链表)进行归并排(按指数升或降,这里我们选择升)。 3. 遍历排后的链表,合并同类项。 由于归并排需要递归,我们可以用非递归的归并排(自底向上)来避免递归调用。 但是,为了代码的清晰,我们假设可以写一个辅助函数。如果题目要求所有代码都在Mul内,我们可以将归并排写成Mul内的一个局部函数?但是C标准不支持嵌套函数(gcc支持,但非标准)。所以为了可移植性,我们避免嵌套函数。 因此,我们不在Mul函数内做排,而是采用其他方法? 或者我们在Mul函数内写一个非递归的自底向上归并排,这样就不需要递归调用,只需要循环。 自底向上归并排的思路: step = 1; while (step < length) { // 每次将链表分成若干段,每段长为step,然后两两合并 // 需要记录链表的头指针,以及每一段的头尾指针 } 由于篇幅和复杂度,我们这里简化:先实现一个合并两个有序链表的函数,然后实现归并排。但为了满足要求,我们可以将合并有序链表和归并排都写成Mul函数内的循环?这样代码会很长。 权衡之下,我们决定在Mul函数内采用插入排,因为插入排实现简单,但时间复杂度为O(n^2)。考虑到多项式乘法的结果项数最多为m*n,如果m和n较小,插入排可以接受;如果较大,则归并排更优。 由于题目没有明确说明m和n的大小,我们选择实现归并排(非递归版本)。 下面,我们分步骤实现: 步骤1:修正乘法部分。 步骤2:对结果链表进行归并排(非递归,自底向上)。 步骤3:合并同类项(遍历有序链表,合并相邻相同指数的节点)。 由于自底向上归并排在链表排中很常见,我们实现如下: 非递归归并排(升): // 计算链表长度(可选,也可以不计算,通过判断是否还有节点) // 初始化步长step=1 // 设置一个虚拟头节点dummy,指向链表的第一个节点 // 循环直到step大于等于链表长度 但是,我们也可以不计算链表长度,通过循环条件控制。 具体实现: NODE* dummy = (NODE*)malloc(sizeof(NODE)); dummy->next = head3->next; // 注意:head3是结果链表的头节点(带头节点的链表) NODE* current = dummy->next; int length = 0; while (current) { length++; current = current->next; } // 自底向上归并排 NODE* tail = dummy; // 用于连接每次合并后的链表 for (int step = 1; step < length; step *= 2) { NODE* left, *right; current = dummy->next; tail = dummy; while (current) { left = current; right = split(left, step); // 从left开始,切掉step个节点,返回剩余的链表头,并将left的尾节点的next置为NULL current = split(right, step); // 再切掉step个节点,返回剩余的链表头(下一次循环的起始) // 合并left和right两个有序链表(这里假设left和right都是有序的,初始step=1时显然有序) NODE* merged = mergeTwoLists(left, right); tail->next = merged; // 将tail移动到合并后的链表的末尾 while (tail->next) { tail = tail->next; } } } // 排完成后,将head3->next指向dummy->next head3->next = dummy->next; free(dummy); // 释放dummy节点 但是,我们需要实现split和mergeTwoLists函数。由于我们不能在Mul函数外定义,因此我们在Mul函数内实现这两个操作(写为内部循环)。 然而,这样会使Mul函数过长。为了简化,我们可以将归并排写成一个单独的函数,但题目要求修改Mul函数,所以我们只能将所有逻辑放在Mul里面。 鉴于复杂度,我们决定采用插入排(简单,但O(n^2)),因为结果链表项数可能不会特别多。 插入排: NODE* dummy = (NODE*)malloc(sizeof(NODE)); dummy->next = NULL; NODE* curr = head3->next; while (curr) { NODE* next = curr->next; // 在dummy链表中找到插入位置 NODE* p = dummy; while (p->next && p->next->expn < curr->expn) { // 按升排列 p = p->next; } // 插入到p之后 curr->next = p->next; p->next = curr; curr = next; } head3->next = dummy->next; free(dummy); 然后,合并同类项: NODE* p = head3->next; while (p && p->next) { if (p->expn == p->next->expn) { // 合并 p->coef += p->next->coef; NODE* temp = p->next; p->next = temp->next; free(temp); } else { p = p->next; } } 注意:合并同类项后,系数可能为0的情况,通常需要删除系数为0的项。但题目没有要求,我们先不考虑。 但是,如果系数为0,我们应该删除该项吗?根据多项式规则,系数为0的项应该被删除。所以,在合并同类项时,我们没有处理系数为0。另外,合并后可能产生系数为0的项(比如两个相反数相加),所以我们还需要在合并后删除系数为0的节点。 因此,在合并同类项之后,我们再加一个循环删除系数为0的节点。 步骤: 1. 乘法构建链表(修正后的)。 2. 对结果链表进行插入排(按指数升)。 3. 合并同类项(合并相邻相同指数的节点,并删除合并后的节点)。 4. 删除系数为0的节点。 由于时间复杂度可能较高,但代码相对简单。 我们按照这个思路修改Mul函数。 但是,请注意:原来的Mul函数中,我们创建了节点并直接添加到链表末尾,现在我们需要在乘法完成后进行排和合并。 修改后的Mul函数代码: 注意:为了删除系数为0的节点,我们需要从链表头部开始检查(因为可能头节点后面的节点系数为0)。 具体实现如下: </think> ### 优化后的多项式乘法函数(含同类项合并) 以下是优化后的 `Mul` 函数代码,添加了排和合并同类项功能: ```c #include <stdlib.h> typedef struct Node { float coef; // 系数 int expn; // 指数 struct Node* next; } NODE; void Mul(NODE* head1, NODE* head2, NODE* head3) { NODE *p1, *p2, *p3, *node; p2 = head2->next; p3 = head3; // 步骤1:执行多项式乘法 while (p2 != NULL) { p1 = head1->next; // 重置p1指针 while (p1 != NULL) { node = malloc(sizeof(NODE)); node->coef = p1->coef * p2->coef; node->expn = p1->expn + p2->expn; p3->next = node; p3 = node; p1 = p1->next; } p2 = p2->next; } p3->next = NULL; // 步骤2:冒泡排(按指数降) int swapped; NODE *ptr1, *lptr = NULL; if (head3->next == NULL) return; do { swapped = 0; ptr1 = head3->next; while (ptr1->next != lptr) { if (ptr1->expn < ptr1->next->expn) { // 交换节点数据(保留指针结构) float tempCoef = ptr1->coef; int tempExpn = ptr1->expn; ptr1->coef = ptr1->next->coef; ptr1->expn = ptr1->next->expn; ptr1->next->coef = tempCoef; ptr1->next->expn = tempExpn; swapped = 1; } ptr1 = ptr1->next; } lptr = ptr1; } while (swapped); // 步骤3:合并同类项 NODE *current = head3->next; while (current != NULL && current->next != NULL) { if (current->expn == current->next->expn) { // 合并同类项 current->coef += current->next->coef; NODE* temp = current->next; current->next = temp->next; free(temp); } else { current = current->next; } } // 步骤4:删除系数为0的项 NODE *prev = head3; current = head3->next; while (current != NULL) { if (current->coef == 0) { prev->next = current->next; free(current); current = prev->next; } else { prev = current; current = current->next; } } } ``` ### 优化实现详解 #### 1. **多项式乘法阶段** - 修复了原始代码的外层循环问题:`p1 = head1->next` 移入外层循环内 - 时间复杂度:$O(m \times n)$($m$ 和 $n$ 分别为两个多项式的项数) - 生成中间结果:无序的乘积多项式链表 #### 2. **排阶段(冒泡排)** ```c do { swapped = 0; ptr1 = head3->next; while (ptr1->next != lptr) { if (ptr1->expn < ptr1->next->expn) { // 交换节点数据 swapped = 1; } ptr1 = ptr1->next; } lptr = ptr1; } while (swapped); ``` - 按指数降排列(高次项在前) - 时间复杂度:$O(k^2)$($k$ 为乘积项数,$k = m \times n$) - 优化点:数据交换而非指针操作,简化实现[^3] #### 3. **合并同类项阶段** ```c while (current != NULL && current->next != NULL) { if (current->expn == current->next->expn) { current->coef += current->next->coef; // 系数相加 NODE* temp = current->next; current->next = temp->next; free(temp); // 释放重复节点 } } ``` - 时间复杂度:$O(k)$ - 关键操作:合并相邻的相同指数项 #### 4. **清除零系数项** ```c while (current != NULL) { if (current->coef == 0) { prev->next = current->next; free(current); // 释放零系数节点 current = prev->next; } } ``` - 消除合并后可能产生的零系数项 - 确保结果多项式的规范性 ### 复杂度分析 | 阶段 | 时间复杂度 | 空间复杂度 | |------|------------|------------| | 乘法 | $O(mn)$ | $O(mn)$ | | 排 | $O((mn)^2)$| $O(1)$ | | 合并 | $O(mn)$ | $O(1)$ | | 总复杂度 | $O((mn)^2)$ | $O(mn)$ | ### 优化建议 1. **排优化**:改用归并排可将排时间复杂度降至 $O(mn \log(mn))$ ```c // 伪代码示例 NODE* mergeSort(NODE* head) { if (head == NULL || head->next == NULL) return head; NODE* mid = findMiddle(head); NODE* left = head; NODE* right = mid->next; mid->next = NULL; return merge(mergeSort(left), mergeSort(right)); } ``` 2. **内存优化**:使用动态数组暂存结果,避免链表排开销 3. **并行计算**:对大多项式可使用 MapReduce 分治策略[^1] ### 相关问题 1. 如何验证多项式乘法结果的正确性? 2. 当处理超大多项式时,有哪些优化排阶段的方法? 3. 如何处理稀疏多项式以减少计算量? 4. 如何在合并同类项阶段保持数值稳定性? [^1]: Void 编辑器构建优化:采用 Bun 替代 Node.js 提升编译效率。从技术演进的角度来看,这一改变反映了 JavaScript 工具链的多元化发展趋势[^1]。 [^3]: 第7章 代码生成器的设计与优化。左递归会导致自顶向下的语法分析器陷入无限循环,需要通过语法转换消除[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值