双链表的基本操作
2015-08-12 17:04
274 查看
在单链表的基本操作中简单说明了单链表相关的问题,双链表与单链表极为相似,所不同的是,双链表的每个结点除了包含数据域
对应单链表的基本操作来看,双链表的基本操作同样包括创建链表、插入结点、删除结点、获取链表长度、逆置链表、链表排序、清空链表、销毁链表。对应操作的方式也基本相似,但是还是有些需要特别注意的地方。
双链表中每个结点都多了一个指针,对于某些操作来说,更加方便了,比如删除结点时,只需要一个临时指针即可。但是,因为要操作更多的指针,为了防止误操作,就要考虑更多的边界条件了。
插入结点时,基本的操作过程是,根据给定的数据创建一个新结点
删除结点时,基本的操作过程是,定位好待删除结点
清空链表的本质就是逐个删除结点,因此,也涉及到删除最后一个结点,需要特殊处理。
相比于单链表的逆置,双链表的逆置要直观一点,只需借助两个指针变量
双链表的排序仍然采用冒泡排序,主要目的还是尽量避免指针的操作,减小出错的可能性。对于冒泡排序,要注意每次循环比较的次数。
DoubleLinkedList.cpp
test.cpp
运行结果
指针真的是一把双刃剑,用得好,它能帮你轻而易举地完成自己想做的事,否则的话,一旦错误出现,你可能得绞尽脑汁才能发现问题所在。根据经验判断,一旦程序编译通过,运行着运行着就意外终止了,极有可能就是哪一处指针的操作出了问题。所以,当你看到一个指针的时候,一定要注意提醒自己,这是一个指针!
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; }
运行结果
指针真的是一把双刃剑,用得好,它能帮你轻而易举地完成自己想做的事,否则的话,一旦错误出现,你可能得绞尽脑汁才能发现问题所在。根据经验判断,一旦程序编译通过,运行着运行着就意外终止了,极有可能就是哪一处指针的操作出了问题。所以,当你看到一个指针的时候,一定要注意提醒自己,这是一个指针!
相关文章推荐
- img镜像的制作
- WPF 实现 DataGrid/ListView 分页控件
- 对原来的模块修改后,最好在解释器里把修改好的代码重新写再粘贴到py文件里,否则F5运行py模块时,总是出错误,如缩进不对 如for语句没写冒号 就导致cmd sdist和install 出错
- 智渔课堂官方免费教程三十七:Java数据结构之单向链表结构
- SVN提交.a文件
- iOS Crash文件分析]-如何使用symbolicatecrash工具
- 时间转换 真机和模拟器错误
- 【Android进阶】(1)使用开源框架AndroidAnnotation
- 【Python】[函数式编程]高阶函数,返回函数,装饰器,偏函数
- Spark MLlib使用有感
- I学霸官方免费教程三十七:Java数据结构之单向链表结构
- 【简单认识】机器学习常见分类算法——朴素贝叶斯
- select(poll)系统调用实现解析(一)
- 关于多线程的一些原则
- hdoj1010(temper of the bone) 解题报告
- java工具类(五)之日期格式字符串与日期实现互转
- 使用jfinal 实现 登陆 注册 验证码检验
- const用法
- dlopen dlerror dlclose dlsym 未定义的引用的解决方案
- java 线程的 run() 没有返回值,怎么办?