数据结构与算法学习笔记----链表

115 阅读4分钟

一、单链表的操作

本文章所书写代码为伪代码,其中会有c语言指针和c++一些简单语法

1.取值 单链表中第i个元素的值

function findData (list L,i,){
	//  初始化 将首元节点赋值给p  并创建计数变量j
    const p = L ->next;j=1
        // 当p不为空  并且校验i的值是否为-1或者0 等边界情况
     while(p&&j<i){
         p=p->next;
         j++
     } 
    // p为空 或者 
    if(!p || j>i)  return error   //第i个元素不存在
        // 返回第i个元素的值
    return p->data    
}

2.查找

2.1 按值查找 根据指定数据返回该值在链表中的位置(该数据的地址)

// 链表L  元素a
function findIndex (list L,a){
    // 将首元节点赋值给p
    const p = L->next
    // 头节点为空 则是空链表
    if(p == null)  return    error
    while(p&&p->data != a){
     //指向p的下一个节点     
        p = p->next   
         return p
    }
   
}

2.2 按值查找 根据指定数据返回该值在链表中的位置序号(是第几个元素)

// 链表L  元素a
function findIndex (list L,a){
    // 将首元节点赋值给p
    const p = L->next
    // 记录是第几个元素
    const i = 1
    // 头节点为空 则是空链表
    if(p == null)  return error    
    while(p&&p->data != a){
     //指向p的下一个节点     
        p = p->next   
        i++
       
    }
    // 找到了就返回位置
    if(p) return i
    // 没找到返回0
    return 0
      
}

3.插入 在第i个节点前面插入e作为新节点

image-20230802001135475.png

// 链表L 新节点e  位置i
function insertNewNode (list L,e,i) {
    const p = L->next ; j=1
    
    // 找到i-1节点  即为e节点的前序节点
    while(p && j<i-1){
        p=p->next
        j++
    }
     if(!p || j>i-1)  return error   //第i个元素不存在
    // new一个新的节点 将s结点的数据域置为e
  	 s = new Node 
     s->data = e
    // 新节点的指针指向 位置i的结点
    s->next = p->next
    // 绑定e的前序结点
    p->next = s
}

4.删除 删除第i个结点

image-20230802230546885.png

//先找到第i个结点  将i-1结点的下一个指针指向i+1结点

function deleteNode(List L ,i){
     const p = L->next ; j=1
     const q
    // 找到i-1节点 
    while(p && j<i-1){
        p=p->next
        j++
    }
    
     if(!p || j>i-1)  return error   //第i-1个元素不存在
    // i-1结点的next域 指向i+1的next域
    p = p->next->next
    // 删除i结点
    delete p->next
}

5.头插法 元素插入在链表的头部

image-20230802232028829.png

function insertHead(List L ,int n){
	L = new LNode;
    L->next = null  //建立一个空的链表
    //循环将结点插入在头部
    for(int i = n ;i>0;--i){
        //创建一个新的结点
	   const p = new Node
       //输入结点的值
       cin>>p->data 
        // 新节点的next指向
       p->next = L->next
       L->next = p
    }

}

6.尾插法 元素插入在链表的尾部

image-20230802233516967.png

function insertTail (List L,int n){
    L = new LNode;
    L->next = null  //建立一个空的链表
    const r = L //创建一个尾指针 r存储当前结点
    for(int i = n ;i>0;--i){
        //创建一个新的结点
	   const p = new Node
       //输入结点的值
       cin>>p->data 
        // 新节点的next指向null 最后一个
       p->next = null
       r->next = p
        // r指向新的结点p
       r=p 
    }
    
}

二、循环链表

定义:循环链表是一种头尾相接的链表(表中最后一个结点的指针域指向头结点形成一个环)

优点:从表中任意一个结点出发可以找到其他结点

image-20230802235044732.png

1.合并两个循环链表(A尾巴->B头->B尾->A头)

function concatList(List A,List B){
    // a为链表A的尾结点  b为链表B的尾结点
    // 存储头结点
    const p  = a->next 
    // 将A链表的尾节点next域 指向B链表的头结点
    a->next = b->next->next
    //删除链表B的头结点
     delete b->next
    // B链表的尾结点链接A链表的头结点
    b->next = p
}

三、双向链表

​ 定义:在单链表的每个结点 里面在增加一个指向其直接前驱的指针域prior,这样链表就形成了有两个方向不同的链

image-20230803000920101.png

1.双向链表插入

image-20230803001606617.png

// 在第i个结点插入新的结点
function insertNode(List L,int i){
    //使用方法找到第i个结点  设p为第i个结点
    // 定义一个新的结点
    const s = new Node
    cin >> s->data
    
    // 新节点的prior存储 i结点的前一个结点
    s->prior = p->prior
    // i结点的前一个结点的next域指向s结点
    p->prior->next = s
    // 新结点s的next域就是p结点
    s->next = p
    //p结点的prior域就是s结点
    p ->prior = s
}

2.双向链表删除结点

image-20230803003552516.png

// 删除第i个节点
function deleteNode(List L,int i){
   // 找到第i个结点为p
    //将p结点的下一个结点的prior赋值给p结点的prior(p的前一个结点)
   // 将a结点复制给c结点的prior域
   p->next->prior = p->prior  
    // 将p结点上一个节点的next域赋值给p结点的next域(p的后一个结点)
     // 将c结点赋值给a结点的next域
   p->prior->next  = p->next 
}

四、单链表、循环链表、双向链表的比较

image-20230803003902991.png

image-20230803225059900.png

image-20230803225202843.png

image-20230803225220954.png