目录
位置:PPT第二章:127
默认前置:
#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit
#include<math.h>//OVERFLOW,exit
#define MAXlength 100 //初始大小为100,可按需修改
typedef int Status; //函数调用状态
struct K
{
float a;
int b;
string c;
};
typedef K Elemtype; //函数调用状态
struct Lnode
//node:结; 结点;
{
Elemtype data;
Lnode* next;
};
typedef Lnode* LinkList;
取第i个元素
project 1:(自己写的,凑合着也能用)
Status 取第i个元素(LinkList L, int i,Elemtype e)
{
if (链表是否为空(L))
cerr << "链表为空" << endl;
if (i < 1)
cerr << "i不对" << endl;
LinkList p = L->next;
int j = 0;
while (p)
{
if (i == j)
{
e = p->data;
break;
}
p = p->next;
j++;
}
return true;
}
project 2:根据课程上写的(算法复杂度低一些,比较好用)
Status GetElem“i”(LinkList L, int i, Elemtype e)
{
LinkList p;
p = L->next;
int j = 1;
while (p && i > j)
{
p = p->next;
j++;
}
if (i<0 || i<j || !p)
return false;
e=p->data;
return true;
}
按值查找(查找其地址,以及是表中第几个元素(位置序号))
project 1:
Status 按值查找地址和位置序号(LinkList L,Elemtype e)
{
LinkList p; int i=1;
p = L->next;
while (p)
{
i++;
if (e == p->data)
{
cout << "地址为: " << p << ";" << endl;
cout << "位置序号为: " << i <<";" << endl;
}
p = p->next;
}
//如果最后运行失败查找不到最后怎么返回ERROR?
if (p = NULL)
return NULL;
return true;
}
但是要注意,如果要这么写的话,在类型K的声明里,还需要加上手撸判断表达式的定义:
struct K
{
float a;
int b;
string c;
bool operator==(K& t)
{
return t.a == a && t.b == b;
//&& t.c = c;
}
};
typedef K Elemtype; //函数调用状态
project 2:根据课程上写的(算法复杂度低一些,比较好用)
Status LocateELem(LinkList L, Elemtype e)
{
//在线性表L中查找值为e的数据元素
//找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
auto p = L->next; int i=1;
while (p && p->data != e)
{
i++;
if (e == p->data)
{
cout << "地址为: " << p << ";" << endl;
cout << "位置序号为: " << i << ";" << endl;
}
p = p->next;
}
if (p == NULL)
return NULL;
return true;
}
同理:
struct K
{
float a;
int b;
string c;
bool operator==(K& t)
{
return t.a == a && t.b == b;
//&& t.c = c;
}
bool operator!=(K& t)
{
return t.a != a || t.b != b;
//|| t.c = c;
}
};
typedef K Elemtype; //函数调用状态
插入(把元素e插到第i个位置结点上)
project 1:
Status 插入(LinkList L,int i,Elemtype e)
{
LinkList p,s; int j = 1;
p = L->next;
s->data = e;
while (p)//&& j < i)
{
if (j == i-1)
{
s->next = p->next;
p->next = s;
return true;
}
p = p->next;
j++;
}
if (!p || j > i - 1)
return false;//别忘了写插入非法时的情况
}
project 2:根据课程上写的
Status Listlnsert(LinkList& L, int i, Elemtype e)
{
auto p = L; int j = 0;
while (p && j < i - 1)
{ p = p->next; ++j; }
if (!p ||j > i - 1)
return false;
auto s = new Lnode;
s->data = e;
s->next=p->next;
p->next = s;
return true;
}//Listlnsert_L
问题:(其实我觉得应该是一样的,只是把这个还没有确定的问题暂时先放在这里mark一下希望来日可以顺利解答)在这个算法里:
int j = 1;p = L->next;
auto p = L; int j = 0;
等价吗
删除(链表中第i个元素结点)
project 1:
Status 删除(LinkList& L, int i)
{
LinkList p,s,q; int j=1;
while (p&&j<i-1)
{
p->next;
j++;
}
s = p->next;
q = s->next;
delete s;
p = q;
return true;
}
project 2:
Status 删除(LinkList& L, int i)
{
LinkList p, s; int j = 1;
while (p && j < i - 1)
{
p->next;
j++;
}
s = (p->next)->next;
delete p->next;
p->next = s;
return true;
}
project 3:根据视频(逻辑更严谨)
Status 删除(LinkList& L, int i)
{
LinkList p = L, s; int j = 1;
while (p && j < i - 1)
{
p = p->next;
j++;
}
if (!p || j > i - 1)
return false;
s = p->next;
p->next = s->next;
//auto e = s->data;
delete s;
return true;
}
各操作的时间复杂度:
单链表的查找、插入和删除:O(n)
线性表的插入和删除:O(1)
单链表的建立(头插法)<倒序插入>
project 1:
用头插法建立链表,并插入(输入)数据结点(这里简化我们只输入3个)a,b,c
Status 头插法(LinkList &L)
{
//创建空链表
K a, b, c;
L= new Lnode;//就一个首元结点
L->next = NULL;
//L->data里面没什么东西
//(我们也不知道里面有啥)
//但可以确定,里面不为空(NULL)
auto p = new Lnode;//(头)插入
L->data = c;
p->next = L->next;
L->next = p;
//每次循环的操作,唯一的区别只有:
//data域输入的数值不同
auto p = new Lnode;
L->data = b;
p->next = L->next;
L->next = p;
//
auto p = new Lnode;
L->data = a;
p->next = L->next;
}
实际上,这个程序是错的,程序设计逻辑:
Points:
关于
L= new Lnode;
实际上我觉得真的是多此一举:
系统开始带有参数LinkList &L的时候不是实际上已经提前给你默认提前分配好了L的内存空间吗,你他*还在这边费劲干啥呢
另外, L= new Lnode;这种开辟空间的格式是哪弄出来的???
原来学过关于new的用法,只有通过定义指针分配新空间,like:
Lnode* p = new Lnode;
但是既然这里可行可用,那我们也需要记住:
L= new Lnode;
即:
<开辟空间首地址> = new <开辟空间存放数据类型>
格式(前面没有定义过记得加auto)
最后经过我们后面深入专门去学习了关于new的使用方法和格式,发现并不是这么一回事:
并不是因为代表L是表,而像我们猜测的那样有了什么新的格式
而是由于表头前面的Linklist &L,表明了他本来就是一个指针,依然属于符合原来的使用规范
也就是说,如果前面(形参传递时)我们已经定义过了该变量,那么在后面开辟空间时
我们就不用(也不能)再(重新)申明变量的类型
详见:
数据结构与算法基础(王卓)(8)附:关于new的使用方法详解_宇 -Yu的博客-CSDN博客_数据结构new
C语言日记 26 指针与函数,动态存储分配_宇 -Yu的博客-CSDN博客
末尾
OK,现在,我们来修正project 1:
注意如果我们想要实现像前面画的图中的“我们想要达到的效果”,那是不可能的了
我们最多只能退而求其次:
让头指针指向头结点,搞一个新的首元结点插进去,而不是搞个新的首元结点(办不到)
project 2:
其实要实现对前面的修正和更改也很简单,只需:
把语句 L->data = (结点信息);修改为:p->data = (结点信息),即可;
Status 头插法(LinkList& L)
{
//创建空链表
K a, b, c;
L = new Lnode;//就一个首元结点
L->next = NULL;//别忘了这句
//L->data里面没什么东西
//(我们也不知道里面有啥)
//但可以确定,里面不为空(NULL)
auto p = new Lnode;//(头)插入
p->data = c;
p->next = L->next;
L->next = p;
//
auto p = new Lnode;
p->data = b;
p->next = L->next;
L->next = p;
//
auto p = new Lnode;
p->data = a;
p->next = L->next;
}
正式根据PPT(148)设计的程序流程来设计实现程序:
Project 3:
Status 头插法()//LinkList &L)
{
//创建空链表
auto L = new Lnode;
//创建新节点
auto p = new Lnode;
K an,an_1;
p->data = an;
//把新节点和链表串起来
p->next = L->next;
L->next = p;
//重复下一轮循环
auto p = new Lnode;
p->next = L->next;
L->next = p;
}
将其实现为我们具体能够落地实现使用的函数:(假设我们输入n个节点的数据)
Status 头插法(LinkList& L, int n)
{
//创建空链表
auto L = new Lnode;
L->next = NULL;//别忘了这句
int i = 1;
while (i <= n)
{
auto p = new Lnode;
cin >> p->data.a;
cin >> p->data.b;
cin >> p->data.c;
p->next = L->next;
L->next = p;
i++;
}
return true;
}
这个结果基本和标准答案差不多,只不过标准答案用的是for语句:
void CreatListHead(LinkList& L, int n)
{
auto L = new Lnode;
L->next = NULL;//别忘了这句
for (int i = n; i > 0; --i)
//for (int i = 0; i < n; ++i)
{
auto p = new Lnode;
cin >> p->data.a;
cin >> p->data.b;
cin >> p->data.c;
p->next = L->next;
L->next = p;
i++;
}
}
最终使用时,不能使返回表和构造表重定义:
Status 头插法(LinkList& A, int n)
{
//创建空链表
auto L = new Lnode;
L->next = NULL;//别忘了这句
int i = 1;
while (i <= n)
{
auto p = new Lnode;
cin >> p->data.a;
cin >> p->data.b;
cin >> p->data.c;
p->next = L->next;
L->next = p;
i++;
}
A = L;
return true;
}
时间复杂度:O(n)
单链表的建立(尾插法)<顺序插入>
project 1:
Status 尾插法(int n)
{
auto L = new Lnode;
L->next = NULL;
LinkList r = L;
for (auto i = 1; i <= n; i++)
{
auto p = new Lnode;
cin >> p->data.a;
cin >> p->data.b;
cin >> p->data.c;
p->next = NULL;
r->next = p;//尾插
r = p;
}
return true;
}
project 2:(同理,不再赘述)
Status 尾插法(LinkList& A, int n)
{
auto L = new Lnode;
L->next = NULL;
LinkList r = L;
for (auto i = 1; i <= n; i++)
{
auto p = new Lnode;
cin >> p->data.a;
cin >> p->data.b;
cin >> p->data.c;
p->next = NULL;
r->next = p;//尾插
r = p;
}
A = L;
return true;
}