精华内容
下载资源
问答
  • ArrayList数组 物理结构连续,并且有自己的下标,因而访问起来效率高,但也因其物理结构连续,插入元素...—补充:LinkedList双向链表的特点是端口和尾端都能进能出,所以从端口和尾端无论是访问还是添加/删除,效率都比从中间
    ArrayList数组 物理结构连续,并且有自己的下标,因而访问起来效率高,但也因其物理结构连续,插入元素时插入位置后的元素都要后移一位,删除同理,故而添加/删除元素的效率不高
    

    LinkedList双向链表,列表中的每个节点都包含了对前一个和后一个元素的引用.访问效率低于ArrayList数组,但添加/删除元素只需要改变前后两个节点,故添加/删除元素的效率高于ArrayList数组.
    —补充:LinkedList双向链表的特点是端口和尾端都能进能出,所以从端口和尾端无论是访问还是添加/删除,效率都比从中间开始的高

    总结:查询用ArrayList,添加/删除用LinkedList

    代码验证:

    public class Num1ArrayVSLinked {
        public static void main(String[] args) {
     //ArrayList数组和LinkedList双向链表效率问题的比较--两个方面:取元素,插入元素
            //1.取元素
            ArrayList<String> arr = new ArrayList<>();
            LinkedList<String> lin = new LinkedList<>();
            for (int i = 0; i < 10000000; i++) {
                arr.add(i, "");
                lin.add(i, "");
            }
            //1.1 从列表的头部开始访问
            long time1 = System.currentTimeMillis();
            arr.get(10);
            long time2 = System.currentTimeMillis();
            System.out.println("ArrayList从列表的头部开始访问的时间:" + (time2 - time1));//0
            long time3 = System.currentTimeMillis();
            lin.get(10);
            long time4 = System.currentTimeMillis();
            System.out.println("LinkedList从列表的头部开始访问的时间:" + (time4 - time3));//0
            //1.2 从列表的中间开始访问
            long time5 = System.currentTimeMillis();
            arr.get(5000000);
            long time6 = System.currentTimeMillis();
            System.out.println("ArrayList从列表的中间开始访问的时间:" + (time6 - time5));//0
            long time7 = System.currentTimeMillis();
            lin.get(5000000);
            long time8 = System.currentTimeMillis();
            System.out.println("LinkedList从列表的中间开始访问的时间:" + (time8 - time7));//31
            //1.3 从列表的尾部开始访问
            long time9 = System.currentTimeMillis();
            arr.get(9999999);
            long time10 = System.currentTimeMillis();
            System.out.println("ArrayList从列表的尾部开始访问的时间:" + (time10 - time9));//0
            long time11 = System.currentTimeMillis();
            lin.get(9999999);
            long time12 = System.currentTimeMillis();
            System.out.println("LinkedList从列表的尾部开始访问的时间:" + (time12 - time11));//0
    
            //2.插入元素
            //2.1 从列表的头部开始插入
            long time01 = System.currentTimeMillis();
            arr.add(10,"3");
            long time02 = System.currentTimeMillis();
            System.out.println("ArrayList从列表的头部开始插入的时间:" + (time02 - time01));//547
            long time03 = System.currentTimeMillis();
            lin.add(10,"3");
            long time04 = System.currentTimeMillis();
            System.out.println("LinkedList从列表的头部开始插入的时间:" + (time04 - time03));//0
            //2.2 从列表的中间开始插入
            long time05 = System.currentTimeMillis();
            arr.add(5000000,"3");
            long time06 = System.currentTimeMillis();
            System.out.println("ArrayList从列表的中间开始插入的时间:" + (time06 - time05));//46
            long time07 = System.currentTimeMillis();
            lin.add(5000000,"3");
            long time08 = System.currentTimeMillis();
            System.out.println("LinkedList从列表的中间开始插入的时间:" + (time08 - time07));//47
            //2.3 从列表的尾部开始插入
            long time09 = System.currentTimeMillis();
            arr.add(9999999,"3");
            long time010 = System.currentTimeMillis();
            System.out.println("ArrayList从列表的尾部开始插入的时间:" + (time010 - time09));//0
            long time011 = System.currentTimeMillis();
            lin.add(9999999,"3");
            long time012 = System.currentTimeMillis();
            System.out.println("LinkedList从列表的尾部开始插入的时间:" + (time012 - time011));//0
        }
    }
    
    
    
    展开全文
  • 总结:以空间换取时间。

    在这里插入图片描述
    总结:以空间换取时间。

    展开全文
  • JavaScript实现双向链表

    2020-08-14 14:22:29
    JavaScript实现双向链表 一、双向链表简介 双向链表:既可以从头遍历到尾,又可以从尾遍历到头。也就是说链表连接的过程是双向的,它的实现原理是:一个节点既有向前连接的引用,也有一个向后连接的引用。 双向...

    JavaScript实现双向链表

    一、双向链表简介

    双向链表:既可以从头遍历到尾,又可以从尾遍历到头。也就是说链表连接的过程是双向的,它的实现原理是:一个节点既有向前连接的引用,也有一个向后连接的引用

    双向链表的缺点:

    • 每次在插入或删除某个节点时,都需要处理四个引用,而不是两个,实现起来会困难些;
    • 相对于单向链表,所占内存空间更大一些;
    • 但是,相对于双向链表的便利性而言,这些缺点微不足道。

    双向链表的结构:

    image-20200227204728456

    • 双向链表不仅有head指针指向第一个节点,而且有tail指针指向最后一个节点;
    • 每一个节点由三部分组成:item储存数据、prev指向前一个节点、next指向后一个节点;
    • 双向链表的第一个节点的prev指向null
    • 双向链表的最后一个节点的next指向null

    双向链表常见的操作(方法):

    • append(element):向链表尾部添加一个新的项;
    • inset(position,element):向链表的特定位置插入一个新的项;
    • get(element):获取对应位置的元素;
    • indexOf(element):返回元素在链表中的索引,如果链表中没有元素就返回-1;
    • update(position,element):修改某个位置的元素;
    • removeAt(position):从链表的特定位置移除一项;
    • isEmpty():如果链表中不包含任何元素,返回trun,如果链表长度大于0则返回false;
    • size():返回链表包含的元素个数,与数组的length属性类似;
    • toString():由于链表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值;
    • forwardString():返回正向遍历节点字符串形式;
    • backwordString():返回反向遍历的节点的字符串形式;

    二、封装双向链表类

    2.0.创建双向链表类

    先创建双向链表类DoubleLinklist,并添加基本属性,再实现双向链表的常用方法:

       //封装双向链表类
        function DoubleLinklist(){
          //封装内部类:节点类
          function Node(data){
            this.data = data
            this.prev = null
            this.next = null
          }
    
          //属性
          this.head = null
          this.tail ==null
          this.length = 0
          }
    

     

    2.1.append(element)

    代码实现:

          //append方法
          DoubleLinklist.prototype.append = data => {
            //1.根据data创建新节点
            let newNode = new Node(data)
    
            //2.添加节点
            //情况1:添加的是第一个节点
            if (this.length == 0) {
              this.tail = newNode
              this.head = newNode 
            //情况2:添加的不是第一个节点
            }else {
              newNode.prev = this.tail
              this.tail.next = newNode
              this.tail = newNode
            }
    
            //3.length+1
            this.length += 1
          }
    

    过程详解:

    添加节点时分为多种情况:

    • 情况1:添加的是第一个节点:只需要让head和tail都指向新节点即可;

    image-20200228094847845

     

    • 情况2:添加的不是第一个节点,如下图所示:只需要改变相关引用的指向即可。

      • 通过:newNode.prev = this.tail:建立指向1;
      • 通过:this.tail.next = newNode:建立指向2;
      • 通过:this.tail = newNode:建立指向3

      要注意改变变量指向的顺序,最后修改tail指向,这样未修改前tail始终指向原链表的最后一个节点。

    image-20200228095048677

     

    image-20200228095135301 

     

    2.2.toString()汇总

    代码实现:

          //将链表转变为字符串形式
          //一.toString方法
          DoubleLinklist.prototype.toString = () => {
            return this.backwardString()
          }
    
          //二.forwardString方法
          DoubleLinklist.prototype.forwardString = () => {
            //1.定义变量
            let current =this.tail
            let resultString = ""
    
            //2.依次向前遍历,获取每一个节点
            while (current) {
              resultString += current.data + "--"
              current = current.prev 
            }
            return resultString
          }
    
          //三.backwardString方法
          DoubleLinklist.prototype.backwardString = () => {
            //1.定义变量
            let current = this.head
            let resultString = ""
    
            //2.依次向后遍历,获取每一个节点
            while (current) {
              resultString += current.data + "--"
              current = current.next
            }
            return resultString
          }
    

    过程详解:

    三种获取字符串的方法:toString()forwardString()backwardString()实现原理相似,仅以backWardString方法为例:

    • 定义current变量记录当前指向的节点。首先让current指向第一个节点,然后通过 current = current.next 依次向后遍历。在while循环中以(current)作为条件遍历链表,只要current != null就一直遍历,由此可获取链表所有节点的数据。

    image-20200228100030713

     

    2.3.insert(position,element)

    代码实现:

          //insert方法
          DoubleLinklist.prototype.insert = (position, data) => {
            //1.越界判断
            if (position < 0 || position > this.length) return false
    
            //2.根据data创建新的节点
            let newNode = new Node(data)
    
            //3.插入新节点
            //原链表为空
              //情况1:插入的newNode是第一个节点
            if (this.length == 0) {
              this.head = newNode
              this.tail = newNode
            //原链表不为空
            }else {
              //情况2:position == 0
              if (position == 0) {
                this.head.prev = newNode
                newNode.next = this.head
                this.head = newNode
              //情况3:position == this.length 
              } else if(position == this.length){
                this.tail.next = newNode
                newNode.prev = this.tail
                this.tail = newNode
                //情况4:0 < position < this.length
              }else{
                let current = this.head
                let index = 0
                while(index++ < position){
                  current = current.next
                }
                //修改pos位置前后节点变量的指向
                newNode.next = current
                newNode.prev = current.prev
                current.prev.next = newNode
                current.prev = newNode
              }
            }
            //4.length+1
            this.length += 1
            return true//返回true表示插入成功
          }
    

    过程详解:

    插入节点可分为多种情况:

    当原链表为空时

    • 情况1:插入的新节点是链表的第一个节点;只需要让head和tail都指向newNode即可。

    image-20200228102437899

    当原链表不为空时

    • 情况2:当position == 0,即在链表的首部添加节点:如下图所示:

    image-20200228103942238

     

    首先,通过:this.head.prev = newNode,改变指向1;

    然后,通过:newNode.next = this.head,改变指向2;

    最后,通过:this.head = newNode,改变指向3;

    image-20200228110014565

    • 情况3:position == this.length,即在链表的尾部添加节点,如下图所示:

    image-20200228105207102

     

    首先,通过:this.tail.next = newNode,改变指向1;(注意这里使用this.tail指向原链表最后一个节点,而不是this.head。因为当length>1时,this.head != this.tail。)

    然后,通过:newNode.prev = this.tail,改变指向2;

    最后,通过:this.tail = newNode,改变指向3;

    image-20200228110745214

    • 情况4:0 < position < this.length,即在链表的中间插入新节点,假设在position = 1的位置插入,如下图所示:

    image-20200228112941682

     

    首先,需要定义变量current按照之前的思路,通过while循环找到position位置的后一个节点,循环结束后index = position

    image-20200228113257650

    image-20200228113257650

    如下图所示:当position = 1时,current就指向了Node2。这样操作current就等同于间接地操作Node2,还可以通过current.prev间接获取Node1。得到了newNode的前一个节点和后一个节点就可以通过改变它们的prev和next变量的指向来插入newNode了。

    image-20200228120701923

    通过:newNode.next = current,改变指向1;

    通过:newNode.prev = current.prev,改变指向2;

    通过:current.prev.next = newNode,改变指向3;

    注意必须最后才修改current.prev的指向,不然就无法通过current.prev获取需要操作的Node1了。

    通过:current.prev = current,改变指向4;

    image-20200228124931441

     测试代码:

        //测试代码
        //1.创建双向链表
        let list = new DoubleLinklist()
    
    	//2.测试insert方法
        list.insert(0, '插入链表的第一个元素')
        list.insert(0, '在链表首部插入元素')
        list.insert(1, '在链表中间插入元素')
        list.insert(3, '在链表尾部插入元素')
        console.log(list);
        alert(list)
    

    2.4.get(position)

    代码实现:

          //get方法
          DoubleLinklist.prototype.get = position => {
            //1.越界判断
            if (position < 0 || position >= this.length) {//获取元素时position不能等于length
              return null
            }
    
            //2.获取元素
            let current = null
            let index = 0
            //this.length / 2 > position:从头开始遍历
            if ((this.length / 2) > position) {
              current = this.head
              while(index++ < position){
              current = current.next
            }
            //this.length / 2 =< position:从尾开始遍历
            }else{
              current = this.tail
              index = this.length - 1
              while(index-- > position){
              current = current.prev
            }
            }
            return current.data
          }
    

    过程详解:

    定义两个变量current和index,按照之前的思路通过while循环遍历分别获取当前节点和对应的索引值index,直到找到需要获取的position位置后的一个节点,此时index = pos =x,然后return current.data即可。

    如果链表的节点数量很多时,这种查找方式效率不高,改进方法为:

    一定要通过this.length来获取链表的节点数否则就会报错。

    • 当this.length / 2 > position:从头(head)开始遍历;
    • 当this.length / 2 < position:从尾(tail)开始遍历;

    image-20200228144005347

     

    2.5.indexOf(element)

    代码实现:

          //indexOf方法
          DoubleLinklist.prototype.indexOf = data => {
            //1.定义变量
            let current = this.head
            let index = 0
    
            //2.遍历链表,查找与data相同的节点
            while(current){
              if (current.data == data) {
                return index
              }
              current = current.next
              index += 1
            }
            return -1
          } 
    

    2.7.update(position,element)

    代码实现:

         //update方法
          DoubleLinklist.prototype.update = (position, newData) => {
            //1.越界判断
            if (position < 0 || position >= this.length) {
              return false
            }
    
            //2.寻找正确的节点
            let current = this.head
            let index = 0
            //this.length / 2 > position:从头开始遍历
            if (this.length / 2 > position) {
              while(index++ < position){
              current = current.next
            }
            //this.length / 2 =< position:从尾开始遍历
            }else{
              current = this.tail
              index = this.length - 1
              while (index -- > position) {
                current = current.prev
              }
            }
    
            //3.修改找到节点的data
            current.data = newData
            return true//表示成功修改
          }
    

    2.8.removeAt(position)

    代码实现:

         //removeAt方法
          DoubleLinklist.prototype.removeAt = position => {
            //1.越界判断
            if (position < 0 || position >= this.length) {
              return null
            }
            
            //2.删除节点
            //当链表中length == 1
            //情况1:链表只有一个节点
            let current = this.head//定义在最上面方便以下各种情况返回current.data
            if (this.length == 1) {
              this.head = null
              this.tail = null
            //当链表中length > 1
            } else{
              //情况2:删除第一个节点
              if (position == 0) {
                this.head.next.prev = null
                this.head = this.head.next
              //情况3:删除最后一个节点
              }else if(position == this.length - 1){
                current = this.tail//该情况下返回被删除的最后一个节点
                this.tail.prev.next = null
                this.tail = this.tail.prev
              }else{
              //情况4:删除链表中间的节点
                let index = 0
                while(index++ < position){
                  current = current.next
                }
                current.next.prev = current.prev
                current.prev.next = current.next
              }
            }
    
            //3.length -= 1
            this.length -= 1
            return current.data//返回被删除节点的数据
          }
    

    过程详解:

    删除节点时有多种情况:

    当链表的length = 1时

    • 情况1:删除链表中的所有节点:只需要让链表的head和tail指向null即可。

    image-20200228153331976

    当链表的length > 1时

    • 情况2:删除链表中的第一个节点:

      通过:this.head.next.prev = null,改变指向1;

      通过:this.head = this.head.next,改变指向2;

      虽然Node1有引用指向其它节点,但是没有引用指向Node1,那么Node1会被自动回收。

    image-20200228162347115

     

    • 情况3:删除链表中的最后一个节点:

      通过:this.tail.prev.next = null,修改指向1;

      通过:this.tail = this.tail.prev,修改指向2;

    image-20200228161946691

    • 情况4:删除链表中间的节点:

    通过while循环找到需要删除的节点,比如position = x,那么需要删除的节点就是Node(x+1),如下图所示:

    image-20200228161648125

     

    通过:current.next.prev = current.prev,修改指向1;

    通过:current.prev.next = current.next,修改指向2;

    这样就没有引用指向Node(x+1)了(current虽指向Node(x+1),但current时临时变量,该方法执行完就会被销毁),随后Node(x+1)就会被自动删除。

    image-20200228162415044

    展开全文
  • C语言实现双向链表

    2020-01-16 22:04:34
    目前我们所学到的链表,无论是动态链表还是静态链表,表中各节点中都只包含一个指针(游标),且都统一指向直接后继节点,通常称这类链表为单向链表(或单链表)。 虽然使用单链表能 100% 解决逻辑关系为 “一对一...

    目前我们所学到的链表,无论是动态链表还是静态链表,表中各节点中都只包含一个指针(游标),且都统一指向直接后继节点,通常称这类链表为单向链表(或单链表)。

    虽然使用单链表能 100% 解决逻辑关系为 “一对一” 数据的存储问题,但在解决某些特殊问题时,单链表并不是效率最优的存储结构。比如说,如果算法中需要大量地找某指定结点的前趋结点,使用单链表无疑是灾难性的,因为单链表更适合 “从前往后” 找,而 “从后往前” 找并不是它的强项。

    为了能够高效率解决类似的问题,本篇文章我们一起来讨论双向链表(简称双链表)。
    从名字上理解双向链表,即链表是 “双向” 的,如下图所示:
    图一

    双向,指的是各节点之间的逻辑关系是双向的,但通常头指针只设置一个,除非实际情况需要。

    从上图中可以看到,双向链表中各节点包含以下 3 部分信息(如下图 所示):

    • 指针域 :用于指向当前节点的直接前驱节点;
    • 数据域 :用于存储数据元素。
    • 指针域:用于指向当前节点的直接后继节点;
      在这里插入图片描述
      因此,双链表的节点结构用 C 语言实现为:
    typedef struct Node
    {
    	struct Node * prior;//指向直接前趋
    	int data;
    	struct Node * next;//指向直接后继
    }Node;
    

    双向链表的创建

    同单链表相比,双链表仅是各节点多了一个用于指向直接前驱的指针域。因此,我们可以在单链表的基础轻松实现对双链表的创建。

    需要注意的是,与单链表不同,双链表创建过程中,每创建一个新节点,都要与其前驱节点建立两次联系,分别是:

    1. 将新节点的 prior 指针指向直接前驱节点;
    2. 将直接前驱节点的 next 指针指向新节点;

    这里给出创建双向链表的 C 语言实现代码:

    Node* initNode(Node * head){
    	head=(Node*)malloc(sizeof(Node));//创建链表第一个结点(首元结点)
    	head->prior=NULL;
    	head->next=NULL;
    	head->data=1;
    	Node * list=head;
    	for (int i=2; i<=3; i++) {
    		//创建并初始化一个新结点
    		Node * body=(Node*)malloc(sizeof(Node));
    		body->prior=NULL;
    		body->next=NULL;
    		body->data=i;
    	  
    		list->next=body;//直接前趋结点的next指针指向新结点
    		body->prior=list;//新结点指向直接前趋结点
    		list=list->next;
    	}
    	return head;
    }
    

    我们可以尝试着在 main 函数中输出创建的双链表,C 语言代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    //节点结构
    typedef struct Node{
    	struct Node * prior;
    	int data;
    	struct Node * next;
    }Node;
    //双链表的创建函数
    Node* initNode(Node * head);
    //输出双链表的函数
    void display(Node * head);
    
    int main() {
    	//创建一个头指针
    	Node * head=NULL;
    	//调用链表创建函数
    	head=initNode(head);
    	//输出创建好的链表
    	display(head);
    	//显示双链表的优点
    	printf("链表中第 4 个节点的直接前驱是:%d",head->next->next->next->prior->data);
    	return 0;
    }
    Node* initNode(Node * head){
    	//创建一个首元节点,链表的头指针为head
    	head=(Node*)malloc(sizeof(Node));
    	//对节点进行初始化
    	head->prior=NULL;
    	head->next=NULL;
    	head->data=1;
    	//声明一个指向首元节点的指针,方便后期向链表中添加新创建的节点
    	Node * list=head;
    	for (int i=2; i<=5; i++) {
    		//创建新的节点并初始化
    		Node * body=(Node*)malloc(sizeof(Node));
    		body->prior=NULL;
    		body->next=NULL;
    		body->data=i;
    
    		//新节点与链表最后一个节点建立关系
    		list->next=body;
    		body->prior=list;
    		//list永远指向链表中最后一个节点
    		list=list->next;
    	}
    	//返回新创建的链表
    	return head;
    }
    void display(Node * head){
    	Node * temp=head;
    	while (temp) {
    		//如果该节点无后继节点,说明此节点是链表的最后一个节点
    		if (temp->next==NULL) {
    			printf("%d\n",temp->data);
    		}else{
    			printf("%d <-> ",temp->data);
    		}
    		temp=temp->next;
    	}
    }
    

    程序运行结果:

    1 <-> 2 <-> 3 <-> 4 <-> 5
    链表中第 4 个节点的直接前驱是:3

    双向链表基本操作

    下面继续讨论有关双向链表的一些基本操作,即如何在双向链表中添加、删除、查找或更改数据元素。

    创建好的双向链表如下图所示:
    在这里插入图片描述

    双向链表添加节点

    根据数据添加到双向链表中的位置不同,可细分为以下 3 种情况:
    添加至表头
    将新数据元素添加到表头,只需要将该元素与表头元素建立双层逻辑关系即可。

    换句话说,假设新元素节点为 temp,表头节点为 head,则需要做以下 2 步操作即可:

    1. temp->next=head; head->prior=temp;
    2. 将 head 移至 temp,重新指向新的表头;

    例如,将新元素 7 添加至双链表的表头,则实现过程如下图 所示:
    在这里插入图片描述
    添加至表的中间位置
    同单链表添加数据类似,双向链表中间位置添加数据需要经过以下 2 个步骤,如下图 所示:

    1. 新节点先与其直接后继节点建立双层逻辑关系;
    2. 新节点的直接前驱节点与之建立双层逻辑关系;

    lxQWmd.gif
    添加至表尾
    与添加到表头是一个道理,实现过程如下(如下图 所示):

    1. 找到双链表中最后一个节点;
    2. 让新节点与最后一个节点进行双层逻辑关系;

    lxQ2OH.gif

    因此,双向链表添加数据的 C 语言代码,参考代码如下:

    Node * insertNode(Node * head,int data,int add){
    	//新建数据域为data的结点
    	Node * temp=(Node*)malloc(sizeof(Node));
    	temp->data=data;
    	temp->prior=NULL;
    	temp->next=NULL;
    	//插入到链表头,要特殊考虑
    	if (add==1) {
    		temp->next=head;
    		head->prior=temp;
    		head=temp;
    	}else{
    		Node * body=head;
    		//找到要插入位置的前一个结点
    		for (int i=1; i<add-1; i++) {
    			body=body->next;
    		}
    		//判断条件为真,说明插入位置为链表尾
    		if (body->next==NULL) {
    			body->next=temp;
    			temp->prior=body;
    		}else{
    			body->next->prior=temp;
    			temp->next=body->next;
    			body->next=temp;
    			temp->prior=body;
    		}
    	}
    	return head;
    }
    
    双向链表删除节点

    双链表删除结点时,只需遍历链表找到要删除的结点,然后将该节点从表中摘除即可。
    例如,删除上面图中的元素2,如下图所示:
    lxliX4.gif]
    双向链表删除节点的 C 语言实现代码如下:

    //删除结点的函数,data为要删除结点的数据域的值
    Node * delNode(Node * head,int data){
    	Node * temp=head;
    	//遍历链表
    	while (temp) {
    		//判断当前结点中数据域和data是否相等,若相等,摘除该结点
    		if (temp->data==data) {
    			temp->prior->next=temp->next;
    			temp->next->prior=temp->prior;
    			free(temp);
    			return head;
    		}
    		temp=temp->next;
    	}
    	printf("链表中无该数据元素");
    	return head;
    }
    
    双向链表查找节点

    通常,双向链表同单链表一样,都仅有一个头指针。因此,双链表查找指定元素的实现同单链表类似,都是从表头依次遍历表中元素。

    C 语言实现代码为:

    //head为原双链表,elem表示被查找元素
    int selectElem(Node * head,int elem){
    //新建一个指针t,初始化为头指针 head
    	Node * t=head;
    	int i=1;
    	while (t) {
    		if (t->data==elem) {
    			return i;
    		}
    		i++;
    		t=t->next;
    	}
    	//程序执行至此处,表示查找失败
    	return -1;
    }
    
    双向链表更改节点

    更改双链表中指定结点数据域的操作是在查找的基础上完成的。实现过程是:通过遍历找到存储有该数据元素的结点,直接更改其数据域即可。

    实现此操作的 C 语言实现代码如下:

    //更新函数,其中,add 表示更改结点在双链表中的位置,newElem 为新数据的值
    Node *amendElem(Node * p,int add,int newElem){
    	Node * temp=p;
    	//遍历到被删除结点
    	for (int i=1; i<add; i++) {
    		temp=temp->next;
    	}
    	temp->data=newElem;
    	return p;
    }
    

    基本上写到这里这篇关于C语言实现双向链表的文章就结束了,总的实现代码已经push到github,喜欢的小伙伴欢迎Star!传送门,小编如果有什么写的不好的地方,欢迎大家留言提出来,多多指教,如果还想了解其他语言实现的数据结构的相关算法,欢迎来我的个人博客相逢了解更多哟!明天继续更新C++语言实现双向链表,坚持就是胜利!加油!

    展开全文
  • Go 双向链表

    2019-06-01 17:45:47
    双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点,相对于单链表来讲:往前往后...
  • java模拟双向链表实现

    千次阅读 2019-03-10 20:11:17
    双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点 下图是双向链表的逻辑结构图...
  • 单向链表、双向链表

    2020-07-12 20:51:54
    单向链表 链表和数组一样,都可以用于存储一系列的元素。链表的每个结点(最后一个结点除外)由一个存储元素本身的结点的数据和一个指向...在数组的起始位置插入和删除数据效率低,改变一个数据需要移动后续所有的数据
  • LinkedList-双向链表

    2020-11-19 11:19:04
    LinkedList-双向链表 《Hash Map源码基于jdk_8》 1. 类的继承关系 双向链表实现了List和Deque(双向队列)接口 2. 变量及其含义 变量名 默认值 含义 其他补充 size 0 地球人都知道 first 头节点 ...
  • 昨天面试官面试的时候问了我一道关于链表的问题:情境如下 面试官:请说一下链表跟数组的区别? 我:数组静态分配内存,链表动态分配内存;数组在内存中连续,链表不连续;...插入和删除效率低(插入和...
  • 【链表】双向链表的基本操作详解(C语言)

    万次阅读 多人点赞 2019-06-10 01:11:59
    他和单链表不同的地方在于:单链表的每个结点的指向只有一个,双向链表每个结点有两个指向。 双向链表结点结构体 双向链表每个结点除了存储数据data外,还有两个指针记录上一个结点和下一个结点的地址,分别是前驱...
  • 相信大家都明白 LinkedList 是基于双向链表而实现的,本篇文章主要讲解一下双向链表的实现,并且我们参考 LinkedList 自己实现一个单链表尝试一下。 什么是链表? 简单的来讲一下什么是链表:首先链表是一种线性的...
  • 数据存储——双向链表 所有的代码都存放在了gitee上,该知识点上所有的源代码见:源代码 首先我们需要了解什么叫链表,通过百度百科的链表可以知道链表的定义:链表是一种物理存储单元上非连续、非顺序的存储结构,...
  • 队列2-双向链表

    2019-01-27 16:43:08
    果然晚了一步,基于双向链表的消息队列模块还没有完全完工,不过已经有一个雏形了,那么本篇文章主要就介绍下双向链表的细节实现以及我基于双向链表搭建的一个消息队列框架,虽说代码还未完全完工,不过不妨,还是...
  • 本文实例讲述了Python单向链表和双向链表原理与用法。分享给大家供大家参考,具体如下: 链表是一种数据结构,链表在循环遍历的时候效率不高,但是在插入和删除时优势比较大。 链表由一个个节点组成。 单向链表的...
  • 双向链表(c++实现)

    千次阅读 2018-02-02 18:14:36
    单向链表的缺点:逆序访问单向链表中的数据元素,效率低下。   若从头节点开始依次访问单向链表的元素,可使用m_current游标,但是逆序访问,只能通过下面代码实现访问: int main(void) { LinkListint> ll; ...
  • 双向链表的实现

    千次阅读 2018-10-15 16:05:03
    相比于数组,链表的查询效率较低,但是增删效率较高,双向链表具有头尾两个节点,每个节点均有三部分组成,前驱指针用来指向前一个节点,后驱指针用来指向后一个节点,另一部分则用来存在数据。与数组一样,访问链表...
  • C语言之链表:单向链表,循环链表,双向链表 提起链式存储结构,其与数组是两个非常基础的数据结构,每当提到链式存储结构时,一般情况下我们都会将其与数组放到一块儿来比较。 对于数组与链表,从结构上来看,数组...
  • 单向链表的时间复杂度 在单向链表原理和实现中已经和动态数组相比对比并...双向链表的时间复杂度 查找节点 因为对节点的添加和删除操作需要查找对于index的节点,首先分析以下查找节点的代码: - (JKRLinkedListNode...
  • LinkedList底层实现(双向链表)(10)

    千次阅读 多人点赞 2020-04-21 17:52:46
    List特性:List底层是双向链表实现的,它的特点是:查询效率低,增删效率高,线程不安全。 1、当对数据存储后需要进行频繁的查询,使用ArrayList 2、但是数据是只用用来存储,增删元素比较频繁那LinkList是你非常好...
  • Redis 使用了 C 语言编写,但因 C 语言是没有内置链表这种结构的,所以 Redis 使用了双向链表结构作为自己需要的实现。 众所周知,链表结构的好处在于不需要连续的的内存空间,以及在插入和删除的时间复杂度是 O(1) ...
  • 由于需要对一组数据多次进行移动操作,所以写个双向链表。但对php实在不熟悉,虽然测试各个方法没啥问题,就是不知道php语言深层的这些指针和unset有什么注意的地方,贴出来让大家教育吧。效率没测试….求谅解~ &...
  • 双向链表的简单实现

    千次阅读 2017-07-10 19:35:21
    双向链表双向链表和单向链表的不同之处是它的指针域有指向前驱的指针pre和指向后驱的指针next。 typedef struct double_list {  int date;  struct double_list *pre;  struct double_list *next; }list;...
  • 实现通用的双向链表(c语言实现)

    千次阅读 2017-10-16 15:46:08
    从实现一个通用的双向链表开始。 1. 构建链表节点   链表节点存值还是存值的地址(指针)?对于通用链表首先要做到能够存放任何数据类型的数据,首先可能会想到的是union,但是数据类型无穷无尽,不可能在union...
  • 他采用HashMap+双向链表实现LRU(淘汰掉最不经常使用的)。先来将原文简单引用介绍下,以免原作者删除。 很久前参加过今日头条的面试,遇到一个题,目前半部分是如何实现 LRU,后半部分是 Redis 中如何实现 LRU。 ...
  • 为什么要写这篇 前几天写的对链表添加尾结点指针,只是对于在链表尾部插入效率高了一些,但是对于从链表尾部删除...对于如何查找链表效率高一些,应该就是二叉树了,不过目前还没怎么接触,之后有时间会实现的。 ...
  • java的单向链表与双向链表

    千次阅读 2019-02-20 16:09:31
    Linkedlist是基于链表实现的,ArrayList是基于数组实现的,它们都不是线程安全的 Linkedlist和ArrayList相比查找比较慢,增删快,为什么? 我们打个比方:LinkedList和ArrayList中都装了10个人。 在ArrayList集合中的10...
  • 双向链表知识总结

    千次阅读 2019-06-05 15:11:56
    双向链表 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造...
  • 头插法建立双向链表

    千次阅读 2020-07-12 21:59:10
    单链表只能向后访问其他节点的数据,若需要寻找某节点前面节点的数据,则需要从表头开始,重新进行遍历,效率不高,为了克服单链表单向性的缺点,可以利用双向链表 双向链表有两个指针域,一个指向直接后继,一个...
  • 二、双向链表增删改查函数声明 三、创建链表 1、链表头动态创建 2、链表头静态创建 四、节点添加 ​1、 头插法 2、 尾插法 3、 位置节点前或后插入 五、节点删除 六、链表清空 七、链表销毁 八、验证程序...
  • Java实现--双向链表

    千次阅读 2018-09-29 12:14:17
    为什么要构造双向链表呢?有什么用呢?《Java数据结构和算法》一书给出了一个例子回答了这两个问题: “假设一个文本编辑器用链表来存储文本。屏幕上的每一行文字作为一个String对象存储在链结点中。当编辑器用户...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 69,211
精华内容 27,684
关键字:

双向链表效率