双链表的基本操作
来源:互联网 发布:软件企业人才需求 编辑:程序博客网 时间:2024/05/22 10:40
在单链表的基本操作中简单说明了单链表相关的问题,双链表与单链表极为相似,所不同的是,双链表的每个结点除了包含数据域data
,指向后继结点的指针域next
外,多了一个指向前一结点的指针域pre
。这样一来,从某一个结点开始,不仅可以向后遍历链表,还可以向前遍历链表。
对应单链表的基本操作来看,双链表的基本操作同样包括创建链表、插入结点、删除结点、获取链表长度、逆置链表、链表排序、清空链表、销毁链表。对应操作的方式也基本相似,但是还是有些需要特别注意的地方。
双链表中每个结点都多了一个指针,对于某些操作来说,更加方便了,比如删除结点时,只需要一个临时指针即可。但是,因为要操作更多的指针,为了防止误操作,就要考虑更多的边界条件了。
插入结点时,基本的操作过程是,根据给定的数据创建一个新结点
newNode
,然后将newNode
插入到head
和首结点之间,在此过程中需要对首结点的指针域赋值,但是,如果链表本身就是一个空链表,那么首结点是不存在,此时任何通过首结点指针操作数据的行为都将导致运行时错误。所以,插入第一个结点的时候,要特殊处理。删除结点时,基本的操作过程是,定位好待删除结点
temp
后,将temp
结点从链表中抽走,只要让temp
结点的前序结点next
指针指向temp
结点的后续结点,同时让temp
结点的后续结点的pre
指针指向temp
结点的前序结点即可。因为定义了头结点,所以无论待删除的结点位于链表中何处,其前序结点都是存在的,但是,如果待删除的结点时链表中的最后一个结点,那么其后续结点也是不存在的,此时只需要将其前序结点的next
指针置空即可。所以,删除最后一个结点时,要特殊处理。清空链表的本质就是逐个删除结点,因此,也涉及到删除最后一个结点,需要特殊处理。
相比于单链表的逆置,双链表的逆置要直观一点,只需借助两个指针变量
p
和temp
(因为可以通过pre
指针访问前序结点)。双链表的排序仍然采用冒泡排序,主要目的还是尽量避免指针的操作,减小出错的可能性。对于冒泡排序,要注意每次循环比较的次数。
代码实现
DoubleLinkedList.h
#ifndef _DOUBLE_LIST_H_#define _DOUBLE_LIST_H_#include <stdio.h>#include <stdlib.h>#include <iostream>#include <iomanip>using namespace std;typedef struct node { int data; struct node * pre; struct node * next;}dNode;dNode * createDList();int getLength(dNode * head);void printDList(dNode * head);bool insertNode(dNode * head, int e);bool deleteNode(dNode * head, int idx);void reverseDList(dNode * head);void sortDList(dNode * head);void emptyDList(dNode * head);void destroyDList(dNode * head);#endif
DoubleLinkedList.cpp
#include "DoubleLinkedList.h"dNode * createDList(){ dNode * head; head = (dNode *)malloc(sizeof(dNode)); if(!head){ return NULL; } head->data = 0; head->pre = NULL; head->next = NULL; return head;}int getLength(dNode * head){ if(!head){ return -1; } return head->data;}void printDList(dNode * head){ dNode * temp; if(!head){ return; } temp = head->next; while(temp){ cout << left << setw(5) << temp->data; temp = temp->next; } cout << endl;}bool insertNode(dNode *head, int e){ dNode * newNode; if(head == NULL){ return false; } newNode = (dNode *)malloc(sizeof(dNode)); if(!newNode){ return false; } newNode->data = e; newNode->next = head->next; newNode->pre = head; if(head->next){ head->next->pre = newNode; } head->next = newNode; head->data ++; return true;}bool deleteNode(dNode * head, int idx){ dNode * temp; int length,i; if(!head){ return false; } length = getLength(head); if(idx>=length){ return false; } temp = head->next; for(i=0;i<length;i++){ if(i == idx){ temp->pre->next = temp->next; if(temp->next){ temp->next->pre = temp->pre; } temp->next = NULL; temp->pre = NULL; free(temp); head->data --; break; } else { temp = temp->next; } } return true;}void reverseDList(dNode * head){ dNode * p, * temp; if(!head){ return; } if(getLength(head) <= 1){ return ; } p = head->next; temp = p->next; p->pre = NULL; while(temp){ p->next = p->pre; p->pre = temp; p = temp; temp = p->next; } p->next = p->pre; p->pre = head; head->next = p;}void sortDList(dNode * head){ int e; int length; int i,j; dNode * p, * q; if(!head){ return ; } length = getLength(head); if(length <= 1){ return; } for(i=1;i<length;i++){ p = head->next; q = p->next; for(j=length-i;j>=1;j--){ if(p->data > q->data){ e = p->data; p->data = q->data; q->data = e; } p = q; q = p->next; } }}void emptyDList(dNode *head){ dNode * temp; if(!head){ return; } if(getLength(head) == 0){ return; } temp = head->next; while(temp){ temp->pre->next = temp->next; if(temp->next){ temp->next->pre = temp->pre; } temp->next = NULL; temp->pre = NULL; free(temp); temp = head->next; } head->data = 0;}void destroyDList(dNode * head){ if(!head){ return; } emptyDList(head); free(head);}
test.cpp
#include "DoubleLinkedList.h"int main(){ int i; dNode * head; int rawData[] = {1,3, 2, 5, 7, 9, 6, 0}; head = createDList(); if(!head){ cout << "can't create double linked list!" << endl; } for(i=0;i<sizeof(rawData)/sizeof(int);i++){ insertNode(head,rawData[i]); } printDList(head); insertNode(head,10); cout << "current list length : " << getLength(head) << endl; printDList(head); deleteNode(head,8); printDList(head); reverseDList(head); printDList(head); sortDList(head); printDList(head); emptyDList(head); cout << "current list length : " << head->data << endl; destroyDList(head); return 0;}
运行结果
指针真的是一把双刃剑,用得好,它能帮你轻而易举地完成自己想做的事,否则的话,一旦错误出现,你可能得绞尽脑汁才能发现问题所在。根据经验判断,一旦程序编译通过,运行着运行着就意外终止了,极有可能就是哪一处指针的操作出了问题。所以,当你看到一个指针的时候,一定要注意提醒自己,这是一个指针!
- 双链表的基本操作
- 双链表的基本操作
- 双链表的基本操作
- 双链表的基本操作
- C++ 双链表的基本操作
- 单链表、双链表的基本操作
- 双链表的基本操作实现
- 数据结构之双链表的基本操作
- 循环双链表的基本操作实现
- 循环双链表的基本操作实现
- 双链表的增删改查基本操作
- SQL的基本操作
- 树的基本操作
- SQL的基本操作
- 单链表的基本操作
- XML的基本操作!
- db2的基本操作
- linux的基本操作
- Active控件开发及部署遇到的问题
- Android应用的性能问题
- Python 3中套接字编程中遇到TypeError: 'str' does not support the buffer interface的解决办法
- Java进阶(十二)JDK版本错误之Unsupported major.minor version 51.0(jdk版本错误)
- Swift学习笔记(二十六)——扩展
- 双链表的基本操作
- maven java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- Android串口通信:串口读写实例
- [ASM]Linux x86_64平台汇编实例
- 搜索引擎核心读书心得1:爬虫质量的3个标准
- 清除浮动方法及优缺点
- 谁是Windows 10中国市场的赢家?
- WebSphere MQ7.5教程——教程 2:将消息发送至远程队列
- Redis报错:ERR Operation against a key holding the wrong kind of value 解决处理