双向链表的基本操作

主要实现了双向链表的在尾部插入,在指定位置插入,前序遍历和后序遍历,以及删除指定节点和删除匹配数据的节点。因为在Windows下使用VS调试用CB写的C代码产生太多问题,因此使用了C++,但是没有使用太多C++的特性,应该很容易移植到C编译器下。

下面是全部代码

DouNode.cpp

  1 #include "iostream"
  2 #include "stdlib.h"
  3
  4 /*宏函数*/
  5 #define log(data) std::cout<<data<<std::endl
  6
  7 #define isNull(ptr);  8 {  9     if(ptr==nullptr){ 10         log("链表为空"); 11         return; } 12 } 13
 14 typedef struct _node_
 15 {
 16     int data;
 17     struct _node_ *pre;
 18     struct _node_ *next;
 19 }node;
 20
 21 /*在尾部加入新节点*/
 22 void addToTail(node *&head,node *&tail, int data)
 23 {
 24     node *p = (node *)malloc(sizeof(node));
 25     p->data = data;
 26     p->pre = nullptr;
 27     p->next= nullptr;
 28     if (tail == nullptr)
 29     {
 30         head = p;
 31         tail = p;
 32     }
 33     else
 34     {
 35         p->pre = tail;
 36         tail->next = p;
 37         tail = p;
 38     }
 39 }
 40
 41 /*指定位置插入*/
 42 void insertByIndex(node *&head, node *&tail, int index, int data)
 43 {
 44     node *tmp,*bak = head;/*备份头部*/
 45
 46     int num = 1;
 47
 48     node *p = (node *)malloc(sizeof(node));
 49     p->data = data;
 50     p->pre = nullptr;
 51     p->next = nullptr;
 52
 53     if (head == nullptr)
 54     {
 55         if (index == 1)
 56         {
 57             head = tail = p;
 58         }
 59         else
 60         {
 61             free(p);
 62             std::cout << "链表为空,仅支持从索引 1 处插入数据" << std::endl;
 63         }
 64         return;
 65     }
 66
 67     while (head != tail && index != num)
 68     {
 69         head = head->next;
 70         ++num;
 71     }
 72
 73     if (index != num)
 74     {
 75         std::cout << "索引越界" << std::endl;
 76         free(p);
 77         head = bak;
 78         return;
 79     }
 80
 81     p->pre = head->pre;
 82     p->next = head;
 83     head->pre->next = p;
 84     head->pre = p;
 85
 86     head = bak;
 87 }
 88
 89 /*前序遍历*/
 90 void forDisplay(node *head,node *tail)
 91 {
 92     isNull(head);
 93     while (head != tail)
 94     {
 95         std::cout << head->data << std::endl;
 96         head=head->next;
 97     }
 98     std::cout << head->data << std::endl;
 99     std::cout << "==END==" << std::endl;
100 }
101
102 /*倒序遍历*/
103 void backDisplay(node *head, node *tail)
104 {
105     isNull(head);
106     while (tail!=head)
107     {
108         std::cout << tail->data << std::endl;
109         tail = tail->pre;
110     }
111     std::cout << tail->data << std::endl;
112     std::cout << "==END==" << std::endl;
113 }
114
115 /*删除第一个匹配的节点*/
116 void deleteData(node *&head, node *&tail,int data)
117 {
118     isNull(head);
119     node *tmp, *bak = head;
120     if (head->data == data)
121     {
122         tmp = head;
123         head = head->next;
124         free(tmp);
125         return;
126     }
127     head = head->next;
128     while (head != tail && head->data!=data)
129     {
130         head = head->next;
131     }
132
133     if (head->next==nullptr)
134     {
135         tmp = tail;
136         tail = tail->pre;
137         tail->next = nullptr;
138         free(tmp);
139     }
140     else
141     {
142         head->pre->next = head->next;
143         head->next->pre = head->pre;
144         free(head);
145     }
146     head = bak;
147 }
148
149 /*删除指定位置的节点*/
150 void deleteByIndex(node *&head, node *&tail, int index)
151 {
152     isNull(head);
153     node *tmp, *bak = head;
154     int num = 2;
155     if (index == 1)
156     {
157         tmp = head;
158         head = head->next;
159         free(tmp);
160         return;
161     }
162     head = head->next;
163     while (head != tail && index != num)
164     {
165         ++num;
166         head = head->next;
167     }
168
169     if (index != num)
170     {
171         std::cout << "索引越界,最大应为"<< num << std::endl;
172         head = bak;
173         return;
174     }
175
176     if (head->next == nullptr)
177     {
178         tail = tail->pre;
179         tail->next = nullptr;
180         free(head);
181         head = bak;
182         return;
183     }
184
185     head->pre->next = head->next;
186     head->next->pre = head->pre;
187     free(head);
188     head = bak;
189 }
190
191 int main(void)
192 {
193     node *head=nullptr;
194     node *tail = nullptr;
195
196     addToTail(head, tail, 1);
197     addToTail(head, tail, 2);
198     addToTail(head, tail, 3);
199     addToTail(head, tail, 4);
200     addToTail(head, tail, 5);
201
202     insertByIndex(head, tail, 2, 123);
203     forDisplay(head, tail);
204
205     deleteByIndex(head, tail, 3);
206     forDisplay(head, tail);
207     system("pause");
208     return 0;
209 }

因为想到的可能有限,因此测试出的结果可能有某些问题,望读者发现后不吝指教。

以上。

时间: 2024-12-07 03:04:38

双向链表的基本操作的相关文章

双向链表的基本操作 C语言

#include<stdio.h> #include<stdlib.h> typedef struct node* DNode; struct node { int data; DNode prior; //前面数据地址 DNode next; //后面数据地址 }; //创建双向链表 void CreatNode(DNode *head) { DNode s; //新节点指针 char e; (*head) = (DNode)malloc(sizeof(struct node))

(续)线性表之双向链表(C语言实现)

在前文实现单向链表的基本操作下,本文实现 双向链表的基本操作. 双向链表与单链表差异,是双向链表结点中有前向指针和后向指针. 所以在插入和删除新结点元素时候不见要考虑后向指针还要考虑 前向指针. 以下是双向链表的C代码: #include<stdio.h> typedef struct node { int data; struct node *next; struct node *prior }Node; //链表的初始化 Node* InitList(int number) { int i

数据结构——双向链表的实现

双向链表主要为了解决单链表找前驱的问题.除了插入.删除操作之外,其他操作与单链表都相同.因此这里只是比较简单的写了双向链表的插入和删除操作.画出结点结构图的话,思路会很清晰,线性表这块还算是比较简单的能够实现. 1 /* 2 在单链表中,求后继的方法NextElem执行的时间为O(1),求前驱的方法PriorElem执行的时间为O(n), 3 引入双向链表就是为了克服单链表这种单向性的缺点. 4 */ 5 6 #include<stdio.h> 7 #include<stdlib.h&g

Nginx 队列双向链表结构 ngx_quene_t

队列链表结构 队列双向循环链表实现文件:文件:src/core/ngx_queue.h/.c.在 Nginx 的队列实现中,实质就是具有头节点的双向循环链表,这里的双向链表中的节点是没有数据区的,只有两个指向节点的指针.需注意的是队列链表的内存分配不是直接从内存池分配的,即没有进行内存池管理,而是需要我们自己管理内存,所有我们可以指定它在内存池管理或者直接在堆里面进行管理,最好使用内存池进行管理.节点结构定义如下: /* 队列结构,其实质是具有有头节点的双向循环链表 */ typedef str

双向链表实现队列与循环链表

一.双向链表(double linked list)如图26.5,是在单链表的每个结点中,再设置一个指向其前驱结点的指针域.双向链表的基本操作与单链表基本一样,除了插入和删除的时候需要更改两个指针变量,需要注意的是修改的顺序很重要,插入如图3-14-5,删除如图3-14-6. 链表的delete操作需要首先找到要摘除的节点的前趋,而在单链表中找某个节点的前趋需要从表头开始依次查找,对于n个节点的链表,删除操作的时间复杂度为O(n).可以想像得到,如果每个节点再维护一个指向前趋的指针,删除操作就像

[数据结构 - 第3章补充] 线性表之双向链表(C语言实现)

一.什么是循环链表? 双向链表(double linked list)是在单链表的每个结点中,再设置一个指向其前驱结点的指针域.所以在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱. 既然单链表也可以有循环链表,那么双向链表当然也可以是循环表. 线性表的双向链表存储结构如下: typedef int ElemType; typedef struct DulNode { ElemType data; //数据域 DulNode *prior; //指向前驱结点的指针 DulN

Java 并发之AbstractQueuedSynchronizer(AQS)源码解析

关键字:CLH,Node,线程,waitStatus,CAS,中断 目录 图解AQS的操作细节 0.前言 1.基本概念 1.1.CAS自旋 1.2.Node 1.3.CLH & AQS 1.4.ReentrantLock 2.图解AQS 2.1.线程A单独运行 2.2.线程B开始运行 2.3.线程C开始运行 2.4.线程A停止运行,线程B继续运行 2.5.1.线程B停止运行,线程C继续运行 2.5.2.线程C放弃竞争 3.问题总结 3.1.为什么在unparkSuccessor操作中从尾节点开始

双向链表排序、插入删除等基本操作

未考虑性能,只是能完成基本功能,应付公司考试而已. 1 // list.cpp : 定义控制台应用程序的入口点. 2 // 3 4 #include "stdafx.h" 5 #include<stdlib.h> 6 typedef struct tag_data 7 { 8 int age; 9 }Data; 10 typedef struct tag_node Node; 11 typedef struct tag_node 12 { 13 Node* pnext; 1

循环双向链表的C++实现

循环双向链表的增删查改等基本操作 #include<iostream> #include<assert.h> using namespace std; typedef int DataType; struct ListNode { DataType _data; ListNode* _prev; ListNode* _next; ListNode(const DataType& x) :_data(x) ,_prev(NULL) ,_next(NULL) {} ListNo