• 数据结构— —双向链表


    双向链表的算法实现

    单链表中每个结点除了存储自身数据之后,还存储了下一个结点的地址,因此可以轻松访问下一个结点,以及后面的后继结点,但是如果想访问前面的结点就不行了,再也回不去了。例如删除结点 p 时,要先找到它的前一个结点 q,然后才能删掉 p 结点,单向链表只能往后走,不能向前走。如果需要向前走,怎么办呢?

    可以在单链表的基础上给每个元素附加两个指针域,一个存储前一个元素的地址,一个存储下一个元素的地址。这种链表称为双向链表.

     

    其结构体定义:

    typedef struct _LinkNode {

    int data; //结点的数据域 struct _LinkNode *next; //下一个节点的指针域

    struct _LinkNode *prev; //上一个结点的指针域

    }LinkNode, LinkList; //LinkList 为指向结构体 LNode 的指针类型

    双向链表的初始

    //前插法

    bool DbListInsert_front(DbLinkList* &L, DbLinkNode *node){ if(!L || !node) return false;

    //1.只有头节点

    if(L->next==NULL){

    typedef struct _DoubleLinkNode { int data; //结点的数据域

    struct _DoubleLinkNode *next; //下一个节点的指针域 struct _DoubleLinkNode *prev; //上一个结点的指针域

    }DbLinkNode, DbLinkList; //LinkList为指向结构体LNode的指针类型

    bool DbInit_List(DbLinkList* &L)//构造一个空的双向链表L

    {

    L=new DbLinkNode; //生成新结点作为头结点,用头指针L指向头结点 if(!L)return false; //生成结点失败

    L->next=NULL; //头结点的next指针域置空

    L->prev=NULL; //头结点的指针域置空 L->data = -1; return true;

    }

    双向链表增加元素前插法

                      node->next=NULL;                           11

    node->prev=L; //新节点prev 指针指向头节点 L->next=node; //头节点next 指针指向新节点

    }else {

    L->next->prev=node;  //第二个节点的prev 指向新节点 node->next = L->next; //新节点next指针指向第二个节点 node->prev=L;    //新节点prev 指针指向头节点

                      L->next=node;            //头节点next 指针指向新节点,完成插入

    }

    return true;

    }

     尾插法

    //尾插法

    bool DbListInsert_back(DbLinkList* &L, DbLinkNode *node){ DbLinkNode *last = NULL; if(!L || !node) return false;

    last = L;

    while(last->next) last = last->next;

    node->next = NULL;

    last->next = node;

    node->prev = last; return true; }

     

    任意位置插入

    //指定位置插入

    bool DbLink_Insert(DbLinkList* &L, int i, int &e){ if(!L||!L->next) return false; if(i<1) return false;

    int j =0;

    DbLinkList *p, *s;

    p = L;

    while(p && j//查找位置为i的结点,p指向该结点 p = p->next;

    j++;

    }

    if(!p || j!=i){ cout<<"不存在节点:"<

    return false;

    } cout<<"p: "<

    s=new DbLinkNode;//生成新节点

    s->data = e;

    s->next = p;

    s->prev = p->prev;

    p->prev->next = s;

    p->prev = s;

    return true;

    }

    双向链表的遍历

    //双向链表的遍历输出

    void DbLink_Print(DbLinkList* &L ){

    DbLinkNode *p = NULL;

    if(!L){

    cout<<"链表为空."<return ;

    }

    p = L;

    while(p->next){

    cout<next->data<<"\t";

    p = p->next;

    }

    //逆向打印

    cout<"逆向打印"<

    while(p){

    cout<data<<"\t";

    p = p->prev;

    }

    cout<

    }

    双向链表获取元素

    bool DbLink_GetElem(DbLinkList* &L, int i, int &e)//双向链表的取值

    {

    //在带头结点的双向链表L中查找第i个元素

    //用e记录L中第i个数据元素的值

    int index;

    DbLinkList *p;

    if(!L || !L->next) return false;

    p = L->next;

    index = 1;

    while(p && index//顺链表向后扫描,直到p指向第i个元素或p为空

    p = p->next;

    index++;

    }

    if(!p || index>i){ return false//i值不合法,i>n或i<=0

    }

    e=p->data; return true;

    }

    11

    双向链表删除元素

    //任意位置删除

    bool DbLink_Delete(DbLinkList* &L, int i) //双向链表的删除

    {

    DbLinkList *p;

    int index = 0;

    if(!L || !L->next){

    cout<<"双向链表为空!"<

    return false;

    }

    if(i<1) return false; //不能删除头节点

    p=L;

    while(p && index

    p = p->next;

    index++;

    }

    if(!p){ //当节点不存在时,返回失败 return false;

    }

    p->prev->next=p->next; //改变删除结点前驱结点的next 指针域 if(p->next){

    p->next->prev = p->prev; //改变删除节点后继节点的prev 指针域

    }

    delete p;         //释放被删除结点的空间

    return true;

    }

    11

    双向链表销毁

    void DbLink_Destroy(DbLinkList* &L) //双向链表的销毁

    {

    //定义临时节点p指向头节点

    DbLinkList *p = L;

    cout<<"销毁链表!"<

    while(p){

    L=L->next;//L指向下一个节点 cout<<"删除元素: "<data<delete p; //删除当前节点

    p = L;   //p 移向下一个节点

    }

    }

    完整代码实现

    1. #include
    2. #include
    3. using namespace std;
    4. typedef struct _DbLinkList
    5. {
    6. int data;//数据域
    7. struct _DbLinkList* prev;//前驱结点
    8. struct _DbLinkList* next;//后继结点
    9. }DbLinkList, DbLinkNode;
    10. bool DbLinkList_Init(DbLinkList*& L)
    11. {
    12. //分配头结点
    13. L = new DbLinkNode;
    14. if (!L)
    15. {
    16. return false;
    17. }
    18. L->next = NULL;
    19. L->prev = NULL;
    20. L->data = -1;
    21. return true;
    22. }
    23. //头插
    24. bool InsertDbLink_front(DbLinkList*& L, DbLinkList* node)
    25. {
    26. if (!L || !node)
    27. {
    28. return false;
    29. }
    30. if (L->next == NULL)
    31. {
    32. node->next = NULL;
    33. node->prev = L;
    34. L->next = node;
    35. }
    36. else
    37. {
    38. L->next->prev = node;
    39. node->next = L->next;
    40. node->prev = L;
    41. L->next = node;
    42. //L->next->prev = node; //第二个节点的 prev 指向新节点
    43. //node->next = L->next; //新节点 next 指针指向第二个节点
    44. //node->prev = L; //新节点 prev 指针指向头节点
    45. //L->next = node;
    46. }
    47. return true;
    48. }
    49. //尾插
    50. bool InsertDbLink_back(DbLinkList* &L, DbLinkNode* node)
    51. {
    52. if (!L || !node)
    53. {
    54. return false;
    55. }
    56. DbLinkList* q;
    57. q = L;
    58. while (q->next)
    59. {
    60. q = q->next;
    61. }
    62. q->next = node;
    63. node->prev = node;
    64. return true;
    65. }
    66. //任意位置插入
    67. bool DbLink_Insert(DbLinkList*& L,int i,int &e)
    68. {
    69. DbLinkList* q, * s;
    70. int j = 1;
    71. q = L->next;
    72. if (!L || !L->next)
    73. {
    74. return false;
    75. }
    76. while (!q || j < i)
    77. {
    78. q = q->next;
    79. j++;
    80. }
    81. if (!q || i != j)
    82. {
    83. return false;
    84. }
    85. s = new DbLinkNode;
    86. s->data = e;
    87. q->prev->next = s;
    88. s->prev = q->prev;
    89. s->next = q;
    90. q->prev = s;
    91. return true;
    92. }
    93. //按指定位置查找元素
    94. bool seekElem(DbLinkList*& L, int i, int& e)
    95. {
    96. DbLinkList* p;
    97. int j = 1;
    98. p = L->next;
    99. if (!L || !L->next)
    100. {
    101. return false;
    102. }
    103. while (p && j < i)
    104. {
    105. p = p->next;
    106. j++;
    107. }
    108. if (!p || j > i)
    109. {
    110. return false;
    111. }
    112. e = p->data;
    113. return true;
    114. }
    115. bool DbLink_Delete(DbLinkList*& L, int i)
    116. {
    117. DbLinkNode* pos;
    118. int j = 1;
    119. pos = L->next;
    120. if (!L || !L->next)
    121. {
    122. return false;
    123. }
    124. if (i < 1)
    125. {
    126. return false;
    127. }
    128. while (!pos ||j
    129. {
    130. pos = pos->next;
    131. j++;
    132. }
    133. if (!pos)
    134. {
    135. return false;
    136. }
    137. pos->prev->next = pos->next;
    138. pos->next->prev = pos->prev;
    139. delete pos;
    140. return true;
    141. }
    142. //链表的销毁
    143. void DestroyLink(DbLinkList* &L)
    144. {
    145. DbLinkNode* q = L;
    146. if (!L)
    147. {
    148. cout << "链表为空" << endl;
    149. }
    150. while (q)
    151. {
    152. L = L->next;
    153. delete q;
    154. q = L;
    155. }
    156. cout << "链表销毁了" << endl;
    157. }
    158. void DbLink_Print(DbLinkList*& L)
    159. {
    160. DbLinkNode* s = NULL;
    161. s = L;
    162. if (!L)
    163. {
    164. cout << "链表为空." << endl;
    165. return;
    166. }
    167. while (s->next)
    168. {
    169. s = s->next;
    170. cout << s->data << "\t";
    171. }
    172. cout << endl;
    173. while (s!=L)
    174. {
    175. cout << s->data << "\t";
    176. s = s->prev;
    177. }
    178. cout << endl;
    179. }
    180. int main(void)
    181. {
    182. DbLinkList* L, * s, * a;
    183. //双向链表初始化
    184. if (DbLinkList_Init(L))
    185. {
    186. cout << "初始化循环链表成功" << endl;
    187. }
    188. else
    189. {
    190. cout << "初始化循环链表失败" << endl;
    191. }
    192. //前插
    193. int j;
    194. cout << "请输入你要插入的个数:";
    195. cin >> j;
    196. for (int i = 0; i < j; i++)
    197. {
    198. s = new DbLinkNode;
    199. cin >> s->data;
    200. InsertDbLink_front(L, s);
    201. }
    202. DbLink_Print(L);
    203. //尾插
    204. int z;
    205. cout << "请输入你要插入的个数:";
    206. cin >> z;
    207. for (int i = 0; i < z; i++)
    208. {
    209. a = new DbLinkNode;
    210. cin >> a->data;
    211. InsertDbLink_front(L, a);
    212. }
    213. DbLink_Print(L);
    214. //任意位置插入
    215. int element, w;
    216. cout << "请输入你要插入的数:";
    217. cin >> w;
    218. cout << "请输入你要插入的位置:";
    219. cin >> element;
    220. DbLink_Insert(L, element, w);
    221. DbLink_Print(L);
    222. //查找元素
    223. int b;
    224. cout << "请输入你要查找元素的位置:";
    225. cin >> b;
    226. seekElem(L, b, element);
    227. cout << element << endl;
    228. //删除指定位置的元素
    229. DbLink_Delete(L, 3);
    230. DbLink_Print(L);
    231. //销毁链表
    232. DestroyLink(L);
    233. DbLink_Print(L);
    234. system("pause");
    235. return 0;
    236. }

  • 相关阅读:
    C内存管理
    PG::Covfefe
    如何在OrangePi AIpro智能小车上实现安全强化学习算法
    单例模式java
    RabbitMQ - 消息堆积问题的最佳解决方案?惰性队列
    突发 Chatgpt之父被开,GPT放开注册,注册难度大幅降低!
    UDP单播和组播通讯之C#设计笔记(十四)
    思科拟推出PuzzleFS驱动,采用Rust语言开发
    python基础语法:复合数据类型
    ClickHouse的Join算法
  • 原文地址:https://blog.csdn.net/m0_65635427/article/details/127392503