数据结构与算法-线性表之双向链表

参考博客:

http://www.cnblogs.com/skywang12345/p/3561803.html

https://blog.csdn.net/howlaa/article/details/38513235

1、概述

线性表是一种线性结构,由数组、单项链表和双向链表组成,这里讲讨论双向链表的理论知识和实现代码。

双向链表和单项链表类似,双向链表由两个指针作为指针域,分别指向前驱节点和后驱节点。可以从任何节点开始向前或者向后删除、增加、查找节点。

双链表的示意图如下:

在插入节点的时候有两种方式:前插法和尾插法,这里介绍的是前插法。如下图所示:

注意,一定要理解这个图,不然理解后面代码的插入操作会有问题

代码描述:

1 void DInsertBefore(DListNode *p,DataType x){
2         //带头节点的双链表中,将值为X的新节点插入P之前,设P!=null
3         DListNode *s = malloc(sizeof(DListNode));//1、这个是申请一个新节点,用来放X的。
4         s->data = x;//2、把新节点的数据放为x
5         s->prior = p->prior;//3、这个是新节点的前驱节点接到原来P的前驱节点上
6         s->next = p;//4、新节点的后节点接到P上
7         p->prior->next = s;//5、这个是把P的前驱节点O的后继节点接到S上
8         p->prior = s;//6、把P的前驱节点接到S上。
9     }  

2、代码编写:

doubleLink.h

#ifndef _DUBLE_LINK_
#define _DUBLE_LINK_

namespace DoubleLinkSpace{

    template<class T>
    class Dnode{
    public:
        T value;
        Dnode *prev;
        Dnode *next;
    public:
        Dnode(){}
        Dnode(T t, Dnode *prev, Dnode *next){
            value = t;
            this->prev = prev;
            this->next = next;
        }
    };

    template<class T>
    class DoubleLink{
    public:
        DoubleLink();
        ~DoubleLink();

        int size();
        bool is_empty();

        T get_fist();
        T get_last();
        T get(int index);

        int insert(int index, T t);
        int insert_first(T t);
        int append_last(T t);

        int del(int index);
        int del_first();
        int del_last();
    private:
        int count;
        Dnode<T> *phead;
        Dnode<T> *get_node(int index);
    };

    //构造函数
    template<class T>
    DoubleLink<T>::DoubleLink(){
        phead = new Dnode<T>();
        phead->next = phead->prev = phead;
        count = 0;
    }

    //析构函数
    template<class T>
    DoubleLink<T>::~DoubleLink(){
        Dnode<T> *ptmp;
        Dnode<T> *pnode = phead->next;
        //删除所有节点
        while (pnode != phead)
        {
            ptmp = pnode;
            pnode = pnode->next;
            delete ptmp;
        }
        delete phead;
    }

    //获取链表节点数
    template<class T>
    int DoubleLink<T>::size(){
        return count;
    }

    //判断链表是否为空
    template<class T>
    bool DoubleLink<T>::is_empty(){
        return (count == 0) ? true : false;
    }

    //二分查找实现链表节点查找
    template<class T>
    Dnode<T> *DoubleLink<T>::get_node(int index){
        if (index < 0 || index >= count)
            return nullptr;
        if (index <= count / 2){
            int i = 0;
            Dnode<T>* pindex = phead->next;
            while (i < index){
                pindex = pindex->next;
                i++;
            }
            return pindex;
        }

        int j = 0;
        int rindex = count - index - 1;
        Dnode<T>* rpindex = phead->prev;
        while (j < rindex){
            rpindex = rpindex->prev;
            j++;
        }
        return rpindex;
    }

    //获取节点的数据域
    template<class T>
    T DoubleLink<T>::get(int index){
        Dnode<T> *tmpNode = get_node(index);
        if (tmpNode != nullptr){
            return tmpNode->value;
        }
        else{
            T ret;
            return ret;
        }

    }

    //获取第一个节点值
    template<class T>
    T DoubleLink<T>::get_fist(void){
        Dnode<T> *tmpNode = get_node(0);
        if (tmpNode != nullptr){
            return tmpNode->value;
        }
        else{
            return 0;
        }

    }

    //获取最后一个节点值
    template<class T>
    T DoubleLink<T>::get_last(void){
        Dnode<T> *tmpNode = get_node(count - 1);
        if (tmpNode != nullptr){
            return tmpNode->value;
        }
        else{
            return 0;
        }
    }

    //前插法插入节点
    template<class T>
    int DoubleLink<T>::insert(int index, T t){
        if (index == 0){
            return insert_first(t);
        }
        Dnode<T> *pindex = get_node(index);
        Dnode<T> *pnode = new Dnode<T>(t, pindex->prev, pindex);//pnode->prev = pindex->prev;pnode->next = pindex
        pindex->prev->next = pnode;
        pindex->prev = pnode;
        count++;
        return 0;
    }

    //在节点头插入
    template<class T>
    int DoubleLink<T>::insert_first(T t){
        Dnode<T> *pnode = new Dnode<T>(t, phead, phead->next);
        phead->next->prev = pnode;
        phead->next = pnode;
        count++;
        return 0;
    }

    //在节点尾插入
    template<class T>
    int DoubleLink<T>::append_last(T t){
        Dnode<T> *pnode = new Dnode<T>(t, phead, phead->next);
        phead->prev->next = pnode;
        phead->prev = pnode;
        count++;
        return 0;
    }

    //删除指定节点
    template<class T>
    int DoubleLink<T>::del(int index){
        Dnode<T> *pindex = get_index(index);
        pindex->next->prev = pindex->prev;
        pindex->prev->next = pindex->next;
        delete pindex;
        count--;
        return 0;
    }

    //删除头部节点
    template<class T>
    int DoubleLink<T>::del_first(){
        return del(0);
    }

    //删除尾部节点
    template<class T>
    int DoubleLink<T>::del_last(){
        return del(count - 1);
    }
}
#endif

doubleLinkTest.cpp

#include <iostream>
#include <string>
#include "doubleLink.h"

using namespace std;
using namespace DoubleLinkSpace;

// 双向链表操作int数据
void int_test()
{
    int iarr[4] = { 10, 20, 30, 40 };

    cout << "\n----int_test----" << endl;
    // 创建双向链表
    DoubleLink<int>* pdlink = new DoubleLink<int>();

    pdlink->insert(0, 20);        // 将 20 插入到第一个位置
    pdlink->append_last(10);    // 将 10 追加到链表末尾
    pdlink->insert_first(30);    // 将 30 插入到第一个位置

    // 双向链表是否为空
    cout << "is_empty()=" << pdlink->is_empty() << endl;
    // 双向链表的大小
    cout << "size()=" << pdlink->size() << endl;

    // 打印双向链表中的全部数据
    int sz = pdlink->size();
    for (int i = 0; i<sz; i++)
        cout << "pdlink(" << i << ")=" << pdlink->get(i) << endl;
}

void string_test()
{
    string sarr[4] = { "ten", "twenty", "thirty", "forty" };

    cout << "\n----string_test----" << endl;
    // 创建双向链表
    DoubleLink<string>* pdlink = new DoubleLink<string>();

    pdlink->insert(0, sarr[1]);        // 将 sarr中第2个元素 插入到第一个位置
    pdlink->append_last(sarr[0]);    // 将 sarr中第1个元素  追加到链表末尾
    pdlink->insert_first(sarr[2]);    // 将 sarr中第3个元素  插入到第一个位置

    // 双向链表是否为空
    cout << "is_empty()=" << pdlink->is_empty() << endl;
    // 双向链表的大小
    cout << "size()=" << pdlink->size() << endl;

    // 打印双向链表中的全部数据
    int sz = pdlink->size();
    for (int i = 0; i<sz; i++)
        cout << "pdlink(" << i << ")=" << pdlink->get(i) << endl;
}

struct stu
{
    int id;
    char name[20];
};

static stu arr_stu[] =
{
    { 10, "sky" },
    { 20, "jody" },
    { 30, "vic" },
    { 40, "dan" },
};
#define ARR_STU_SIZE ( (sizeof(arr_stu)) / (sizeof(arr_stu[0])) )

void object_test()
{
    cout << "\n----object_test----" << endl;
    // 创建双向链表
    DoubleLink<stu>* pdlink = new DoubleLink<stu>();

    pdlink->insert(0, arr_stu[1]);        // 将 arr_stu中第2个元素 插入到第一个位置
    pdlink->append_last(arr_stu[0]);    // 将 arr_stu中第1个元素  追加到链表末尾
    pdlink->insert_first(arr_stu[2]);    // 将 arr_stu中第3个元素  插入到第一个位置

    // 双向链表是否为空
    cout << "is_empty()=" << pdlink->is_empty() << endl;
    // 双向链表的大小
    cout << "size()=" << pdlink->size() << endl;

    // 打印双向链表中的全部数据
    int sz = pdlink->size();
    struct stu p;
    for (int i = 0; i<sz; i++)
    {
        p = pdlink->get(i);
        cout << "pdlink(" << i << ")=[" << p.id << ", " << p.name << "]" << endl;
    }
}

int main()
{
    int_test();        // 演示向双向链表操作“int数据”。
    string_test();    // 演示向双向链表操作“字符串数据”。
    object_test();    // 演示向双向链表操作“对象”。

    return 0;
}

3、测试结果

----int_test----
is_empty()=0
size()=3
pdlink(0)=30
pdlink(1)=20
pdlink(2)=10

----string_test----
is_empty()=0
size()=3
pdlink(0)=thirty
pdlink(1)=twenty
pdlink(2)=ten

----object_test----
is_empty()=0
size()=3
pdlink(0)=[30, vic]
pdlink(1)=[20, jody]
pdlink(2)=[10, sky]
请按任意键继续. . .

原文地址:https://www.cnblogs.com/veryStrong/p/9096697.html

时间: 2024-10-12 04:41:30

数据结构与算法-线性表之双向链表的相关文章

数据结构与算法--线性表系列(循环链表、双向链表)

hello,everybody,今天我们来学习线性表的最后两种形式,循环链表.双向链表.这两种链表,是链式存储结构的不同形式.书归正传,我们先来看看循环链表吧. 大家思考一个问题,我们把线性表各个元素比作下图的路线图上的城市: 我们的线性表各个结点的指针,都是指向唯一的后继结点,线性表的终端结点的指针为空.这样的话,如果我们在南京,我们需要先访问南京右j边的城市,再访问南京左边的城市.根据线性表的结构,我们只能返回上海,从上海依次访问到北京.因为我们的终端结点的指针为空,如果直接访问南京右边的城

数据结构与算法—线性表详解

前言 通过前面数据结构与算法前导我么知道了数据结构的一些概念和重要性,那么我们今天总结下线性表相关的内容.当然,我用自己的理解解分享给大家. 其实说实话,可能很多人依然分不清线性表,顺序表,和链表之间的区别和联系! 线性表:逻辑结构, 就是对外暴露数据之间的关系,不关心底层如何实现. 顺序表.链表:物理结构,他是实现一个结构实际物理地址上的结构.比如顺序表就是用数组实现.而链表用指针完成主要工作.不同的结构在不同的场景有不同的区别. 对于java来说,大家都知道List接口类型,这就是逻辑结构,

数据结构与算法-线性表

近期在学习数据结构,反反复复已经看过几遍了,也做了一些练习题,但总感觉不记录一下,思路就不是很清晰,所以,从今天开始总结这段时间对数据结构的学习. 无论学习什么,基础知识都是最总要的,数据结构也不例外.线性表就是数据结构的基础,很多常见的数据结构都是基于线性表来实现的. 那么,什么是线性表呢?官方的定义是: 零个或多个数据元素的有限序列 可以从两个方面来理解线性表,首先它是一个序列,也就是其中的元素有先后顺序,其次是有限的,对于无线数列,也只能存在于理论数学中. 说了这么多,小结一下: 1)线性

数据结构与算法——线性表顺序存储结构

今天总结一下数据结构中的线性表中的顺序存储结构,这是一种比较简单的结构. 首先,看一下什么是线性表. 什么是线性表? 线性表是一种简单的数据结构,数据元素之间是一对一的关系,即除了第一个和最后一个元素外其余元素都是首尾相接的.元素的个数称为线性表的长度,长度为零则表示线性表为空. 什么是线性表的循序存储结构? 线性表中的顺序存储结构就是把线性表中的元素按逻辑次序依次存放在一组地址连续的存储空间中,也把这种线性表称为顺序表.根据顺序表的特点,通常是用数组来存储元素的. 下面就看具体的实现(C++)

数据结构与算法-线性表的实现(1)

今天来说说线性表的实现 这里以List作为例子 package com.ray.testobject; public class List { private int length; private Man[] array; public int getLength() { return length; } public void setLength(int length) { this.length = length; } public Man[] getArray() { return ar

数据结构与算法-线性表顺序存储结构删除操作的实现

这一章节我们来看一下线性表顺序存储结构删除操作的简单实现 package com.ray.testobject; public class Test { private Object[] list; public Object[] getList() { return list; } /** * 初始化list * * @param num * 元素个数 */ private void iniList(int num) { list = new Object[num]; for (int i =

数据结构与算法-线性表的定义与特点

1.线性表概念 线性表是由零个或者多个数据元素组成的有序的序列. 图示: 2.特点 2.1 有序 我们可以从上图看见,线性表里面的元素是一个挨着一个顺序排下去的,就像平常小朋友排队等放学的样子 2.2 允许零元素,也就是空表 2.3 第一个元素有且仅有一个后继,最后一个元素有且仅有一个前驱,其他元素有且仅有一个前驱以及有且仅有一个后继 我们可以从上图看见,线性表里面第一个元素a1,他没有前驱,只有一个a2的后继,最后一个元素an,只有一个前驱a(n-1),没有对应的后继,其他某个元素ai,它有且

数据结构与算法——线性表

1.概念 线性表可以看做一种抽象的概念,也可以作为一种抽象数据类型,一个线性表是某类元素的集合,还记录着元素之间的一种顺序关系.相当于一个抽象类,只做定义. 2.具体实现 1.顺序表 顺序表的基本实现方式非常简单:表中元素顺序存放在一片足够大的连续储存区间里,首元素存入储存区的开始位置,其余元素依次顺序存放,元素之间的逻辑关系通过元素在储存区里的物理位置表示(隐式表示元素之间的关系) 顺序表在内存中的布局方式: 1.顺序表基本操作的实现 创建和访问操作 创建空表时,需要分配一块元素储存,记录表的

java数据结构和算法------线性表(顺序表结构)

1 package iYou.neugle.list; 2 3 public class MySeqList<T> { 4 private int initMaxSize = 10; 5 private T[] list; 6 private int listLen = 0; 7 8 public MySeqList() { 9 this.Init(); 10 } 11 12 public MySeqList(int size) { 13 this.initMaxSize = size; 14