最近在学习算法导论,为了督促自己 就把学习过程中的代码记录下来。
就先从最简单的链表写起,准确的说应该是双链表。大致先简单的介绍一下链表的优缺点,以便在后面对应的数据结构中使用该结构。
优点:链表在内存中存储并不是连续的,可以很方便的进行插入和删除操作。
缺点:由于链表的不连续存储特性,导致索引操作不能使用下标进行,因此对链表进行搜索操作时间复杂度是O(n)级别的。
以下是自己根据算法导论上面的设计书写的代码,链表的操作有插入、删除、搜索。
头文件:
//name:myList1.h
#ifndef MY_LIST1_H
#define MY_LIST1_H
#include<iostream>
#include<memory>
using namespace std;
template<typename T>
class myList1{
struct list_node{
list_node* prev;
T data;
list_node* next;
list_node(){
prev = NULL;
next = NULL;
}
list_node(list_node* node){
this->data = node->data;
this->prev = node->prev;
this->next = node->next;
}
list_node(T value){
this->data = value;
this->next = this->prev = NULL;
}
};
private:
list_node* list_head; //链表的头
//list_node* list_rear; //链表的尾
int count_size; //链表中元素的个数
public:
myList1(){
list_head = NULL;
count_size = 0;
}
~myList1(){ }
//给链表的头部插入节点x
void insert_head(list_node* x){
x->next = list_head;
if (list_head != NULL)
list_head->prev = x;
list_head = x;
x->prev = NULL;
count_size++;
}
void insert_head(T value){
//----------------------------------------------------------
//此处如果使用 list_node* x=list_node(value)
//表示在栈中对x分配了内存,那么后面的list_head指向x之后
//当x的函数块结束,x会被释放,list_head将变成野指针
//因此必须使用new在堆中进行内存分配
//---------------------------------------------------------
list_node* x = new list_node(value);
//shared_ptr<list_node> x = make_shared<list_node>(value);
insert_head(x);
}
//搜索链表中第一个值为value的节点,并返回该节点的指针
list_node* search_first_value(T value){
list_node* temp = list_head;
while (temp != NULL&&temp->data != value)
temp = temp->next;
return temp;
}
//删除链表中的节点x
void delete_list_node(list_node* x){
if (x->prev != NULL)
x->prev->next = x->next;
else
list_head = x->next;
if (x->next != NULL)
x->next->prev = x->prev;
count_size--;
}
//删除链表中第一个值为value的节点
void delete_value(T value){
list_node* delete_node = search_first_value(value);
delete_list_node(delete_node);
count_size--;
}
//显示链表中的数据data
void display(){
list_node* temp = list_head;
while (temp != NULL){
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
};
#endif
以下是测试的代码:
//name:main.c
#include<vector>
#include"myList1.h"
int main(){
vector<int> test_data = {1,2,3,4,5};
myList1<int> test_list = myList1<int>();
for (int i = 0; i < test_data.size(); i++){
test_list.insert_head(test_data[i]);
}
test_list.display();
test_list.delete_value(1);
test_list.display();
return 0;
}
本来打算自己实现一下STL中关于List源码,但是能力有限,还需继续学习才能完成,下面在给出STL中List的相关函数及功能
push_back()、push_front():把某个值插入到list的尾部或者头部。
pop_back()、pop_back():删除list中的第一个或者最后一个元素。
insert():这个方法即可以把某个元素插入到指定的位置,也可以把一个指定范围的多个元素插入到list中迭代器所指向的位置,另外还可以把某个具体的多个备份插入到list中迭代器所指定的位置。
erase():主要用来删除list中的元素,即可以删除list中某个位置的单个元素,也可以删除list中的某个范围内的所有元素对象。
clear():该函数主要用来删除list中的所有元素。
merge()函数:用于把两个list对象合并成一个list对象。
remove()函数:删除list中的对象可以使用pop_back(),pop_front(),erase()和clear()等常见函数,在list中同时提供了remove()函数,函数remove()的语法格式为void remove(const T& value)
remove会把list对象中所有等于参数的元素删除。如果list存储的是类,且类中有指针,由于remove不会自动删除类的存储空间,所以一般不能用remove方法对类元素直接删除。
remove_if():remove()函数用于无条件删除所有等于参数值的list成员元素,有时需要满足一定的条件才能把它删除,这时需要使用条件删除函数:remove_if(),函数remove的语法格式为templace<class Pred>void remove_if(Pred pr)
sort()函数:偏于list对象排序,在list成员函数中专门定义了一个成员函数sort,用于对list对象进行排序,函数sort的语法格式为void sort(); void sort(greater<T> pr)
splice()函数:merge()函数可以将两个list对象合并在一起,但是该函数不太灵活,list容器类提供了另一个函数splice。格式为void splice(iterator position, list& x); void splice(iterator position, list& x, iterator it); void splice(iterator position, list& x, iterator first, iterator last)