数据结构C++复习笔记

线性表

1.线性表

线性表是一个有限序列。

线性表基于数组存储的表示叫做顺序表。常用数组作为表。

线性表基于指针的存储表示叫做链表。通常有单链表、双链表、循环链表等。

2.顺序表

0x01顺序表的定义和特点

假设顺序表A的起始存储位置为Loc(1),第i个表项的存储位置为Loc(i)则有:

Loc(i)=Loc(1)+(i-1)*sizeof(T)

其中,Loc(1)为第一个表项的存储位置,即数组中第0个元素的位置。

0x02顺序表的类定义及操作

顺序表存储分为静态存储和动态存储。

静态存储
#include <iostream>   //顺序表静态存储
#define maxSize 100
using namespace std;  

typedef int T;   //typedef 类型定义
typedef struct{
    T data[maxSize];
    int n;
}Seqlist;
int main()
{
    Seqlist a;
    T m;
    for(T i=0;i<3;i++){
        cin >> m;
        a.data[i] = m;
    }
    for(T i=0;i<3;i++){
        cout << a.data[i] << ' '
    }
return 0;
}
动态存储
typedef int T;  //动态存储
typedef struct {
    T *data;   //指针new新的数组
    int maxSize,n;  
}Seqlist;
顺序表的类声明和部分操作
#include <iostream>
const int defaultSize=100;
using namespace std;
template<class T>
class SeqList{
protected:
    T * data;
    int maxSize;
    int last;
public:
    Seqlist(int sz=defaultSize); //构造函数
    SeqList(SeqList<T>& L); //复制构造函数
    ~SeqList(){delete[]data;} //析构函数
    int Size()const{return maxSize;} //常成员函数返回最大可容纳表项个数
    int Length()const{return last+1;} //计算表长度
    int Search(T &x)const; //查找x在表中的位置,并返回序号
    int Locate(int i)const; //定位第i个表项
    bool getData(int i,T&x)const; //取第i个表项的值
    bool Insert(int i,T&x); //插入x在第i个表项之后
    bool Remove(int i,T&X); //删除第i个表项,通过x返回表项的值
    bool Isempty(); //判断是否为空表
    bool Isfull(); //判断表是否为满表
    void Input();  //输入
    void Output(); //输出
};

const成员函数无法改变它的对象的数据成员的值,同时const成员函数无法调用非const成员函数。

1.构造函数和复制构造函数
//构造函数
template<class T>
SeqList<T>::SeqList(int sz){
    if(sz>0){
        maxSize=sz;
        last=-1;
        data=new T[maxSize];  //动态分配空间
        if(data==0){
            cerr <<"存储分配错误"<< endl;exit(1);
        }
    }
}
//复制构造函数
template<class T>
SeqList<T>::SeqList(SeqList<T>& L){
    maxSize=L.Size();
    last=L.Length()-1;
    data=new T[maxSize];
    if(data==0){
       cerr << "存储分配错误" << endl;exit(1);
    }
    for(int i=0;i<=last;i++){
            data[i]=L.data[i];
    }
}
2.搜素和查找函数
//搜索函数
template<class T>
int SeqList<T>::Search(T&x)const{
    for(int i=0;i<=last;i++){
        if(data[i]==x)return i+1;
    }
return 0;
}
//查找函数
template<class T>
int SeqList<T>::Locate(int i)const{
    if(i<0||i>last+1)cout <<"查找位置错误";
    else if(i>=1&&i<=last+1)return i;
}
3.插入和删除操作
//插入操作
template<class T>
bool SeqList<T>::Insert(int i,T&x){
    if(last==maxSize-1)return false; //表满
    if(i<0||i>last+1) return false;	//插入位置不合理
    for(int j=last;j>=i;j--){	   //第i个元素其key值为i-1
        data[j+1]=data[j];
    }
    data[i]=x;
    last++;
    return true;

}
//删除操作
template<class T>
bool SeqList<T>::Remove(int i,T&x){
    if(last==-1)return false;
    if(i<0||i>last+1)return false;
    x=data[i-1];
    for(int j=i;j<=last;j++){
        data[j-1]=data[j];
    }
    last--;
    return true;
}
4.输入输出和赋值操作
//输入操作
template<class T>
void SeqList<T>::Input(){
    while(1){
        cin >> last;
        if(last<=maxSize-1)break;
    }
    for(int i=0;i<=last;i++){
        cin >> data[i];
    }
}
//输出操作
template<class T>
void SeqList<T>::Output(){
    for(int i=0;i<=last;i++){
        cout << data[i] <<" ";
    }

}
0x03顺序表的应用

交运算和并运算中通常会用两个顺序表来进行操作。

3.单链表

采用链接方式来存储线性表,通常将链接方式存储的线性表称为链表。链表常用于插入或删除比较频繁,存储空间需求不定的情形。

0x01单链表的概念

单链表的一个存储结点Node包含两个部分,一部分为data域,用于存储线性表的数据元素,link部分为指针数据域,存放一个指针,该指针指向链表中下一个结点的存储地址。

链表中的第一个结点的地址可以通过链表的头指针first找到,其他结点的地址则在前驱结点的link域中,链表的最后一个结点没有后继,在结点的指针域中放一个空指针NULL。

0x02单链表的类定义

单链表通常有两个类,第一个为结点类(linknode)和链表类(list)。

复合类
//用复合类表示单链表
class List;
class LinkNode{
friend class List;
private:
    int data;
    LinkNode *Link;
};
class List{
private:
    LinkNode *first;
public:

};

LinkNode成员不能直接使用List的私有成员,但List类所有成员都可以直接使用LinkNode的私有成员。

嵌套类
class List{
private:
    class LinkNode{
private:
    int data;
    LinkNode *link;
    };
    LinkNode *first;
};


由于是嵌套定义的,LinkNode为私有成员,所以List类外部的对象和函数无法访问LinkNode类的对象。

基类和派生类
class LinkNode{
private:
    int data;
    LinkNode *link;
};
class List:public  LinkNode{
private:
    LinkNode *first;

};

struct定义LinkNode类
struct LinkNode{
    int data;
    LinkNode *link;
};
class List{
private:
    LinkNode *first;
};

0x03单链表的插入和删除

插入主要是有两个步骤,第一步就是将newNode的指针域指向被插结点的后一个结点,(newNode->link=current->link)第二个就是被插结点的指针域指向newNode。(currnet->link=newNode)。

在这里插入图片描述
删除主要有三个步骤,第一个就是找出要删除的结点(del)以及其前一个结点(current),第二个就是将current的指针域指向被删结点的下一个结点,第三个就是删除要删除的结点。

在这里插入图片描述

//单链表的插入算法
bool List::Insert(int i,int &x){
//i=0时意味插入第一个结点之前,first指针指向新的结点
if(i==0||first==NULL){
    LinkNode *newNode=new LinkNode(x);
    if(newNode==NULL){
            cerr << "存储空间分配错误。";exit(1);
    }
    newNode->link=first;
    first=newNode;
}
//无论插入表中还是表尾,都是一样的操作
else{
    LinkNode *current=first;
    for(int j=1;j<i;j++){
        if(current=NULL)break;
        else current=current->link;
    }
    if(current==NULL){cerr<<"无效的插入位置";return false;}
    else{
        LinkNode *newNode=new LinkNode(x);
        newNode->link=current->link;
        current->link=newNode;
    }
}
return true;
}
//删除算法
bool List::Remove(int i,int &x){
//将链表中的第i个元素删去,i从1开始
LinkNode* del,* current;
    if(i==1){
        del=first;
        first=del->link;
        delete del;
    }
    else{
        current=first;
        for(int j=1;j<i-1;j++){   //寻找current结点
            if(current==NULL)break;
            else current=current->link;
        }
        if(current==NULL||current->link==NULL){
            cerr << "删除位置错误";exit(1);
        }
        del=current->link;
        current->link=del->link;
    }
    x=del->data;  //取出被删除结点中的数据值
    delete del;
    return true;
}
0x04带附加头结点的单链表

插入头结点的目的是在空表或非空表第一个结点之前的插入可以不作为特殊情况来处理,可以统一处理。

为了统一操作,在表的最前端设置附加头结点,本身不带数据,仅标志表头。

在这里插入图片描述

0x05单链表的模板类

带有附加头结点的单链表模板类的定义。

template<class T>
struct LinkNode{
    T data;
    LinkNode<T> *link;
    LinkNode(LinkNode<T>* ptr=NULL){link=ptr;}
    LinkNode(T item,LinkNode<T> *ptr=NULL){
        data=item;
        link=ptr;
    }
};
template<class T>
class List{
private:
    LinkNode<T> *first;
public:
    List(){first=new LinkNode<T>;} //构造函数
    List(T&x){first=new LinkNode<T>(x);} //构造函数
    List(List<T>&L);
    ~List(){makeEmpty();}//析构函数
		void makeEmpty();//置空表
};
//置空表
template<class T>
void List<T>::makeEmpty(){
    LinkNode<T> *q;
    while(first->link!=NULL){  //头结点的指针域不为空,就删除后面的结点
        q=first->link;
        first->link=q->link;
        delete q;
    }
}
1.插入和删除
//在附加头结点中插入算法
template<class T>
bool List<T>::Insert(int i,T&x)
{
    LinkNode<T>* current=Locate(i);
    if(current==NULL) return false;
    LinkNode<T> * newNode=new LinkNode<T>(x);
    if(newNode==NULL){
        cerr << "内存分配错误"; exit(1);
    }
    newNode->link=current->link;
    current->link=newNode;
    return true;
}
//删除算法
template<class T>
bool List<T>::Remove(int i,T& x)
{
    LinkNode<T>* current=Locate(i-1);
    if(current==NULL||current->link==NULL)return false;
    LinkNode<T>* del=Locate(i);
    current->link=del->link;
    x=del->data;delete del;
    return true;
}
2.计算链表长度和定位函数
//计算带有附加头结点的链表的长度
template<class T>
int List<T>::Length(){
    LinkNode<T>*p=first->link;int count=0;  //p指向第一个结点
    while(p!=NULL){
        p=p->link;
        count++;
    }
    return count;
}
//定位函数,并返回该结点的地址
template<class T>
LinkNode<T>* List<T>::Locate(int i){
    LinkNode<T>* p=first; int j=0;
    while(p!=NULL&&j<i){
        p=p->link;
        j++;
    }
    return p;
}
3.前插法建立链表

主要有两步操作

(1)生成新结点,将读入数据存放到新结点的data域中。

(2)将该新结点插入到链表的前端,直到读入结束符为止。

template<class T>
void List<T>::inputFront(T endtag)
{
    LinkNode<T>* newNode;
    T val;
    makeEmpty();
    cin >> val;
    while(val!=endtag){
        newNode=new LinkNode<T>(val);
        if(newNode==NULL)cerr << "内存分配错误";exit(1);
        newNode->link=first->link;   //newNode的指针域现在为空
        first->link=newNode;
        cin >> val;
    }
}
int 
4.后插法建立链表
template<class T>
void List<T>::inputRear(T endtag)
{
    LinkNode<T>* newNode,*last;
    T val;
    makeEmpty();
    cin >> val;
    last=first;
    while(val!=endtag){
        newNode=new LinkNode<T>(val);
        if(newNode==NULL)cerr << "内存分配错误";exit(1);
        last->link=newNode;
        last=newNode;
        cin >> val;
    }
    last->link=NULL;
}
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值