数据结构(线性表)
相关的C/C++基础知识
- typedef 语句的使用
//①声明一个结构体,或者为 一个类型修改名字方便理解。
typedef struct xxx{
int xxxx;
}newName;
//②把int 变量名 改为NewInt型
typedef int NewInt;
- ElemType的定义和使用(DataType的定义和使用)
/*可表示任意一种基本类型
比如: typedef int ElemType
*/
//可以模板函数的类型参数 解决该问题
template <typename T>
void opooc(T t){
cout<<t;
}
- new和delete的使用(malloc()和free()的使用)
/*
动态new一个含100个int类型大小的地址
int *p = new int[100];
p指向第一个元素的地址
使用完一定要删除 delete []p;
如果只有一个元素则可以delete p;
在类中调用的时候要把new函数放在构造函数里,把delete放在析构函数中
例如:
*/
class opooc{
public:
opooc();
~opooc();
int *p;
};
opooc::opooc(){
p = new int[10];
cout<<"created"<<endl;
}
opooc::~opooc(){
delete []p;
cout<<"deleted"<<endl;
}
/*
c语言中 使用 malloc开辟空间,使用free释放空间
int *p = (int *)malloc( 100);
free p;
其中第一个括号放 空间地址存放元素的类型,第二个括号必须填字节数
sizeof()可以计算类型的大小,如果要计算数组的大小的时候,一定记得要传数组,不要传数组的指针。
如果要使用形参数组的长度,一定要在每次传参的时候传值。
或者把数据包装成一个结构,结构中有一个字段是长度,另外一个字段是数据内容
*/
/*
代码在系统的中的心路历程:
https://www.cnblogs.com/kekec/p/3238741.html
源文件->
预处理[主要是做一些代码文本的替换工作。(该替换是一个递归逐层展开的过程。)]->
编译(词法分析(lex)、语法分析(yacc)、语义分析及优化,优化,生成汇编代码)->
汇编(汇编代码->机器指令。)->
链接(这里讲的链接,严格说应该叫静态链接。多个目标文件、库->最终的可执行文件(拼合的过程)。分配静态存储空间到栈)
运行(分配动态空间到堆)
*/
- 元素的位序和元素的存储下标
位序是用户看的,元素的储存下标是计算机采用的;
不同语言不一样,python 可以给定数组的下表范围(比如-100 到 xx)
- 函数的返回值及类型Status的定义
status提高可读性
//自定义throw抛出异常
class PerException{
public:
PerException(string str);
};
PerException::PerException(string str){
try {
throw str.c_str();
} catch (const char* e) {
cout<<e;
exit(0);
}
}
- 常量的定义(MAXSIZE等)和使用
#define X 100
const int x = 100;
//注意:使用define定义不能加分号
- 引用调用参数的定义和使用
//m 对应了传入的参数,不分配内存
void test(int &m){
m++;
}
- 数据结构中一些常用变量的定义问题
循环控制变量i,j,k等,指针变量p,q,r等
线性表的类型定义
- 类型定义
线性表是由零个或者多个数据元素组成的有序的序列。
线性表的存储包括顺序存储和链式存储
- 相关的基本操作:
//初始化
void initList(T &L)
//清空
void clearList(T &L)
//插入
bool insert(T &L,int local,int data)
//删除
int deleteSeq(T &L, int local)
//定位
int locate(T L,int res)
//取第i个元素:
int getIndexOf(T L,int local)
//求表的长度:
int length(T L)
线性表的顺序存储结构
//顺序存储结构
typedef struct {
int arr[MAXSIZE];
int length;
}SeqList;
//初始化
void initList(SeqList &L){
for (int i = 0; i<MAXSIZE; i++) {
L.arr[i] = 0;
}
L.length =0;
}
//清空
void clearList(SeqList &L){
for (int i = 0; i<MAXSIZE; i++) {
L.arr[i] = 0;
}
L.length = 0;
}
//插入
bool insert(SeqList &L,int local,int data){
if (L.length == MAXSIZE) {
PerException("the length of L is more than MAXSIZE");
}
if (local<0||local>L.length) {
PerException("the local is less than 0 or it is greater than length");
}
// length =5
// 01234
for (int i = L.length; i > local; i--) {
L.arr[i] = L.arr[i-1];
}
L.arr[local] = data;
L.length++;
for (int i = 0 ; i < L.length; i++) {
cout << L.arr[i]<<" ";
}
cout << endl;
return true;
}
//删除
int deleteSeq(SeqList &L, int local){
if (L.length == 0) {
PerException("the length of L is 0");
}
if(local < 0|| local>=L.length){
PerException("the local is less than 0 or it is equal or greater than length");
}
int res = L.arr[local];
for (int i=local+1; i<L.length; i++) {
L.arr[i-1] = L.arr[i];
}
L.arr[L.length-1] =0;
L.length--;
return res;
}
//定位
int locate(SeqList L,int res){
int local =-1;
for(int i=0;i<res;i++){
local = L.arr[i]==res?i:local;
}
//返回-1说明没有该元素
return local;
}
//取第i个元素:
int getIndexOf(SeqList L,int local){
if (local < 0||local>=L.length) {
PerException("the local is less than 0 or it is equal or greater than length");
}
return L.arr[local];
}
//求表的长度:int length(L)
int length(SeqList L){
return L.length;
}
// 测试
int main(){
SeqList l;
initList(l);
insert(l, 0, 46);
insert(l, 1, 32);
insert(l, 2, 52);
insert(l, 3, 62);
insert(l, 4, 82);
for (int i = 0 ; i < l.length; i++) {
cout << l.arr[i]<<" ";
}
cout<<endl;
deleteSeq(l,2);
for (int i = 0 ; i < l.length; i++) {
cout << l.arr[i]<<" ";
}
cout << endl;
deleteSeq(l,3);
for (int i = 0 ; i < l.length; i++) {
cout << l.arr[i]<<" ";
}
cout << endl;
return 0;
}
线性表链式存储结构(带表头结点)
//定义
(1)typedef struct LNode{
int data;
LNode* next;
}LNode,* LinkList;
//初始化
void initList(LinkList &L){
LNode* p = new LNode;
p->next =nullptr;
L =p;
};
//清空
void clearList(LinkList& L){
LNode *p = L->next;
L->next = nullptr;
while (p != nullptr) {
LNode* q = p;
p = p->next;
delete q;
}
}
//插入
//local以0位基点,头结点位置为-1
bool insert(LinkList& L ,int local,int x){
if (local < 0) {
PerException(" the local is less than 0");
}
LNode* p = L;
int count = -1;
while (p != nullptr && count < local-1) {
p = p->next;
count++;
}
if (p == nullptr) {
PerException("the local is more than size");
}else{
LNode* q = new LNode;
q->next = p->next;
q->data = x;
p->next = q;
}
return true;
}
//删除
int deleteLNode(LinkList& L,int local){
if (local<0) {
PerException("");
}
//初始化要返回的值
int data = 0;
int count = -1;
LNode* p = L;
while (p != nullptr && count <local -1) {
p = p->next;
count++;
}
if (p == nullptr || p ->next ==nullptr) {
PerException("");
}else{
LNode* q = p -> next;
data = q->data;
p->next = q->next;
delete q;
}
return data;
}
//定位
int locate(LinkList L ,int data){
//指向L作为头结点的next
LNode* p = L->next;
int count = 0;
while (p!= nullptr && p->data != data) {
p = p->next;
count++;
}
if(p == nullptr ){
PerException("");
}
return count;
}
//取第i个元素
int getIndexOf(LinkList L ,int local){
LNode* p =L;
int count =-1;
int data = 0;
while (p != nullptr && count < local) {
p = p->next;
count++;
}
if (p == nullptr) {
PerException("");
}else{
data = p->data;
}
return data;
}
//求链长
int length(LinkList L){
int count = 0;
LNode* p = L->next;
while (p != nullptr) {
count++;
p = p->next;
}
return count;
}
//打印顺序链
void printLinkList(LinkList L){
LNode* p =L->next;
while (p != nullptr ) {
cout<<p->data<<" " ;
p= p->next;
}
cout<<endl;
}
//测试数据
int main(){
LinkList L;
initList(L);
insert(L, 0, 24);
insert(L, 1, 35);
insert(L, 2, 37);
insert(L, 3, 88);
insert(L, 4, 31);
insert(L, 5, 23);
printLinkList(L);
deleteLNode(L, 3);
printLinkList(L);
deleteLNode(L, 1);
printLinkList(L);
cout<<getIndexOf(L, 3)<<endl;
cout<<length(L)<<endl;
cout<<locate(L, 23)<<endl;
clearList(L);
printLinkList(L);
return 0;
}
顺序存储和链式存储的比较
存储空间的连续性?
链式存储是动态存储空间分配,存储空间不具有连续性
顺序存储静态存储空间分配,存储空间具有连续性随机存取否?
随机存取就是直接存取,可以通过下标直接访问的那种数据结构,与存储位置无关,顺序存储。
非随机存取就是顺序存取了,不能通过下标访问了,只能按照存储顺序存取,与存储位置有关,链式存储。插入/删除操作的效率?
顺序存储的效率低 (需要遍历)
链式存储的效率高 (直接找位置)有无附加的存储空间?
顺序表没有附加存储空间;
单链表有附加存储空间;- 那种数据结构更好?(空间 时间)
但是不能笼统的说那种数据结构更好。
作为一般规律,当线性表中元素个数变化较大或者未知时,最好使用链表;
如果实现知道线性表的大致长度,使用顺序表的空间效率会高;
但是还要考虑到时间效率,如果经常插入删除,还是首先考虑链式存储结构。
循环链表
- 定义
形如:A→B→C→D→A
- 结构体
typedef struct LNode
{ int data;
LNode * next;
}CLNode, * CLinkList;
- 实现插入操作
//实现插入(带表头结点)
bool insert(CLinkList& L, int i, int x)
{
int j=-1;
LNode *p=L;
while (p->next!=L &&j<i-1){
p=p->next;
j++;
}
if ( j < i-1 )
return -1;
//只要j==i-1, 无论p->next是否等于L都是可以插入的
LNode* q = new LNode;
q->data=x;
q->next=p->next;
p->next=q;
return 1;
}
初始化循环列表:让first指针的next指向first;
插入:让p节点指向first,循环遍历到要插入的位置Local的上一个结点,操作和单链表一样,只不过在循环的时候控制停止的时候,
要判断p的next是否为first。也可以用双指针。也要考虑,插入的位置是否越界。
删除:同插入,再不过判断结束时,判断next是否为first
双向链表
- 定义
形如: A←→B←→C←→D
- 结构体
typedef struct DNode
{ int data;
DNode *prior;
DNode *next;
} DNode, *DLinkList;
实现(带表头结点)
p指向一个结点:
如何在p前面(后面)插入一个q结点?
前面插入:
q->next = p->prior->next
p->prior->next = q
q->prior = p->prior
p->prior =q
后面插入:
q->next = p->next
p->next = q
q->prior = p->next->prior
p->next->prior = q如何删除p后面(前面)的结点q?
删除前面:
q= p->prior
q->prior->next=p
p->prior = q->prior
delete q
删除后面:
q=p->next
q->next->prior = p
p->next = q->next
delete q- 如何删除p指向的结点?
p->prior->next =p->next
p->next->prior =p->prior
delete p
线性表的应用
1.一元多项式的表示及相加
请参考链接:https://blog.youkuaiyun.com/opooc/article/details/81188258
2.约瑟夫环
请参考链接:https://blog.youkuaiyun.com/opooc/article/details/81151050
3.卡特兰数
请参考链接:https://blog.youkuaiyun.com/opooc/article/details/81139165