下午上机的时候大概地实现了链表的基本功能。写的时候也不是光是脑袋想,
就在word里面画了个粗糙的图形,边看边写。刚刚开始的时候功能可以不要
太多。把最基本的功能先实现,也就是数据定义,default constructor和destructor的功能
。然后测试,再增加功能,这样后来写的时候出错的时候就会很明朗,至少不会是前面写的
function出错了。g++和vc下调试通过。main里面的测试只是其中的一部分,写的时候删了许多。
双向循环链表。首先它是一个环状的,只是不是那么圆,就像一个蛇咬住了自己的尾巴,那个发现苯环
的人就是晚上做了个梦,蛇咬住了自己的尾巴,然后他发现了苯环的结构。灵感源自生活,所以我们程序员
虽然总是对着电脑,但是请不要忘了,离开了电脑我们还有很广阔的世界,说多了哈,刚刚打了下酱油。
接着上面的。然后它又是双向的,所以它应该有2个指针,一个就是pre(前驱),一个就是next(后继)。
就像右边这个图里面画的那样,画的不咋样,这个还是到寝室后重新画的。
清楚了它的结构,实现起来就比较简单了,某些功能比单链表实现起来更简单点,毕竟它是双向的,所以很灵活,链表的用途还是很广泛的,os里面的各种作业调度算法的实现都是和链表息息相关。所以它的重要性可见一斑了。
如果你自己感兴趣的话也可以自己去实现一下,C/C++都行。
链表的学习到这里就结束了,对数据结构,linux C/C++有着浓厚兴趣的同学可以加群91926913一起交流下。
最后请看下面的代码。
转载请注明出处,谢谢!
dclink.h
#ifndef DCLINK_H
#define DCLINK_H
//双向循环链表
typedef int datatype;
//方便修改
//当然也可以写成模板来适应更多的数据类型
struct dclink{
datatype data;//数据定义
struct dclink *pre;
struct dclink *next;//前驱和后继指针
};
class DCLink
{
public:
DCLink();//default constructor
DCLink(datatype data);//单参constructor
void add(datatype data);//添加data到链表中去
datatype getData(int pos)const;//获得指定位置的数据
int deleteData(int pos);//删除指定位置的数据
int modify(int pos, datatype data);//更改指定位置的数据
int insert(int pos, datatype data);//在指定位置插入数据
void sort()const;//循环链表排序
int rePrint()const;//双向循环链表转置没啥意义,转置输出还有那么点意义
int print()const;//打印链表
~DCLink();//destructor
int getLength()const;//得到链表的长度
private:
DCLink operator=(const DCLink &dcl){}//assignment constructor 禁止
DCLink (const DCLink &dcl){}//copy constructor 禁止
struct dclink *head;//头指针
struct dclink *cur;//当前指针
int size;//大小
};
#endif
DCLink.cpp
#include "dclink.h"
#include <iostream>
//default constructor
DCLink::DCLink(){
head = cur = NULL;//默认为空
size = 0;
}
DCLink::DCLink(datatype data){//单参constructor
head = new struct dclink[1];//申请空间
cur = head;//指向当前节点
head->data = data;
head->next = head->pre = head;//指向自身
size = 1;
}
void DCLink::add(datatype data){//添加data到链表中去
//默认添加到表尾
struct dclink *dcl = new struct dclink[1];
dcl->data = data;
if (NULL != head){//表非空
//当前节点为第1号节点,它的后继节点为第2号节点
struct dclink *temp = cur->next;//保持2号节点的位置
cur->next = dcl;//1号节点的后继和新增节点相连
dcl->pre = cur;//新增节点的前驱和1号节点相连
dcl->next = temp;//新增节点的后继和2号节点相连
temp->pre = dcl;//新增节点和2号节点的前驱相连
}else {
head = dcl;//新加节点成为头结点
head->data = data;
head->next = head->pre = head;//指向自身
}//已经添加完毕,新增节点成为当前节点
cur = dcl;
size++;//长度+1
}
int DCLink::deleteData(int pos){//删除指定位置的数据
if (size >= pos && pos > 0){//有数据并且没有越界才显示
int count = 1;//计数
struct dclink *temp = head;
while (pos != count){
temp = temp->next;//直到到达指定的位置
count++;
}//先到达指定位置
//分情况是因为如果删除最后一个节点会改变cur的状态,挂空指针
if (size == pos){
if (1 == size){//只有一个节点的时候
delete []temp;
head = cur = NULL;//置空
size--;//-1
return 0;
}else{//删除最后一个节点
cur = temp->pre;//向前移动一个位置
}
}else{//如果删除第一个节点head会改变
if (1 == pos){
head = temp->next;//向后移动一个位置
}
}
//当前节点为0号节点,后继节点为1号节点,前驱节点为-1号节点
temp->pre->next = temp->next;//-1号节点的后继和1号节点相连
temp->next = temp->pre;//1号节点的前驱和-1号节点相连
size--;//长度-1
return 0;//成功返回0
}
return -1;//无数据或者越界返回-1
}
int DCLink::modify(int pos, datatype data){//更改指定位置的数据
if (size >= pos && pos > 0){//有数据并且没有越界才显示
int count = 1;//计数
struct dclink *temp = head;
while (pos != count){
temp = temp->next;
count++;
}
temp->data = data;//更新
return 0;
}
return -1;//无数据或者越界返回-1
}
int DCLink::insert(int pos, datatype data){//在指定位置插入数据
if (0 == size && 1 == pos){
this->add(data);//直接调用add函数
return 0;
}
if (size >= pos && pos > 0){//有数据并且没有越界才显示
int count = 1;//计数
struct dclink *dcl = new struct dclink[1];
dcl->data = data;
struct dclink *temp = head;
while (pos != count){
temp = temp->next;//直到到达指定的位置
count++;
}//先到达指定位置
//分情况是因为如果插入到第一个节点会改变head的状态
if (size == pos){
if (1 == size){//只有一个节点的时候
head = dcl;//当前结点成为头结点
head->next = temp;//新结点的后继和旧头结点相连
temp->pre = head;//旧头结点的前驱和新结点相连
head->pre = temp;//新结点的前驱和旧头结点相连
temp->next = head;//旧头结点的后继和新结点相连
}else{//插入到尾结点的前面
temp->pre->next = dcl;
dcl->pre = temp->pre;
dcl->next = temp;
temp->pre = dcl;
}
size++;
return 0;
}else{
if (1 == pos){//插入到第一个位置
head = dcl;//当前结点成为头结点
head->next = temp;//新结点的后继和旧头结点相连
temp->pre = head;//旧头结点的前驱和新结点相连
head->pre = temp->pre;//新结点的前驱和旧头结点相连
temp->pre->pre = head;//旧头结点的后继和新结点相连
}else {//插入到中间的其它位置
temp->pre->next = dcl;
dcl->pre = temp->pre;
dcl->next = temp;
temp->pre = dcl;
}
size++;
return 0;
}
}
return -1;//越界返回-1
}
datatype DCLink::getData(int pos)const{//获得指定位置的数据
if (size >= pos && pos > 0){//有数据并且没有越界才显示
int count = 1;//计数
struct dclink *temp = head;
while (pos != count){
temp = temp->next;//比插入和删除简单很多
count++;//+1,第一次写的时候忘了+1,然后就固执地认为getData肯定没问题
//可bug就在这里
}
return temp->data;
}
return -1;//无数据或者越界返回-1
}
void DCLink::sort()const{//排序
if (1 < size){
//快速排序
int i = 1;
int j = 0;
struct dclink *ohead = head;
while (size != i){//循环size - 1次
j = 0;//重置
struct dclink *temp = ohead;//辅助指针
while (j != size - i){
if (ohead->data > temp->next->data){//交换排序
ohead->data += temp->next->data;
temp->next->data = ohead->data - temp->next->data;
ohead->data -= temp->next->data;
}
temp = temp->next;//移动
j++;
}
ohead = ohead->next;//前面j个数据已经排好
i++;
}
}
}
int DCLink::rePrint()const{//打印链表
if (NULL != head){//链表非空
struct dclink *temp = head;
int count = 0;//计数
while (size != count){
temp = temp->pre;
std::cout<<temp->data<<std::endl;
count++;
}
return 0;
}
return -1;//空表返回-1
}
int DCLink::print()const{//打印链表
if (NULL != head){//链表非空
struct dclink *temp = head;
int count = 0;//计数
while (size != count){
std::cout<<temp->data<<" ";
temp = temp->next;
count++;
}
return 0;
}
return -1;//空表返回-1
}
int DCLink::getLength()const{
return size;
}//得到链表的长度
//destructor
DCLink::~DCLink()
{
while (0 != size){//用size来控制析构的次数
struct dclink *temp = head;//辅助指针
head->pre->next = head->next;//让head的前一个节点指向它的后一个节点
head = head->next;//head后移动一个节点
head->pre = temp->pre;//head还是指向前一个节点
delete []temp;
size--;
}
}
int main(void){
DCLink dcl;
for (int i = 100; i > 0; i--)
dcl.add(i);
dcl.print();
std::cout<<std::endl;
dcl.sort();
dcl.print();
dcl.modify(1,10);
dcl.modify(5,44);
dcl.modify(3,33);
dcl.deleteData(5);
dcl.deleteData(1);
dcl.deleteData(3);
dcl.deleteData(6);
dcl.add(5);
for (i = 1; i < 7; i++)
std::cout<<dcl.getData(i)<<std::endl;
std::cout<<"the sizeof DCLink is "<<dcl.getLength()<<std::endl;
dcl.print();
return 0;
}