`轻松搞定数据结构(线性表篇)

数据结构(线性表)

相关的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;
}

顺序存储和链式存储的比较

  1. 存储空间的连续性?
    链式存储是动态存储空间分配,存储空间不具有连续性
    顺序存储静态存储空间分配,存储空间具有连续性

  2. 随机存取否?
    随机存取就是直接存取,可以通过下标直接访问的那种数据结构,与存储位置无关,顺序存储。
    非随机存取就是顺序存取了,不能通过下标访问了,只能按照存储顺序存取,与存储位置有关,链式存储。

  3. 插入/删除操作的效率?
    顺序存储的效率低 (需要遍历)
    链式存储的效率高 (直接找位置)

  4. 有无附加的存储空间?
    顺序表没有附加存储空间;
    单链表有附加存储空间;

  5. 那种数据结构更好?(空间 时间)
    但是不能笼统的说那种数据结构更好。
    作为一般规律,当线性表中元素个数变化较大或者未知时,最好使用链表;
    如果实现知道线性表的大致长度,使用顺序表的空间效率会高;
    但是还要考虑到时间效率,如果经常插入删除,还是首先考虑链式存储结构。

循环链表

  • 定义

形如: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.csdn.net/opooc/article/details/81188258
2.约瑟夫环
请参考链接:https://blog.csdn.net/opooc/article/details/81151050
3.卡特兰数
请参考链接:https://blog.csdn.net/opooc/article/details/81139165

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值