最近想回过头来看看以前写的一些代码,可叹为何刚进大学的时候不知道要养成写博客的好习惯。现在好多东西都没有做记录,后面也没再遇到相同的问题,忘的都差不多了。只能勉强整理了下面写的一些代码,这些代码有的有参考别人的代码,但都是自己曾经一点点敲的,挂出来,虽然很基础,但希望能对别人有帮助。
链表
链表是一种非常基本的数据结构,被广泛的用在各种语言的集合框架中。
首先链表是一张表,只不过链表中的元素在内存中不一定相邻,并且每个元素都可带有指向另一个元素的指针。
链表有,单项链表,双向链表,循环链表等。
单项链表的数据结构
如下
1 typedef struct NODE{ 2 struct NODE * link; 3 int value; 4 } Node;
对链表的操作
主要有增删查
1 Node * create(){ 2 Node * head,* p,* tail; 3 // 这里创建不带头节点的链表 4 head=NULL; 5 do 6 { 7 p=(Node*)malloc(LEN); 8 scanf("%ld",&p->value); 9 10 if(p->value ==0) break; 11 // 第一次插入 12 if(head==NULL) 13 head=p; 14 else 15 tail->link=p; 16 tail=p; 17 } 18 while(1); 19 tail->link=NULL; 20 return head; 21 } 22 23 int delet(Node **linkp,int del_value){ 24 register Node * current; 25 Node * m_del; 26 27 //寻找正确的删除位置,方法是按顺序访问链表,直到到达等于的节点 28 while((current = *linkp)!=NULL && current->value != del_value) 29 { 30 linkp = ¤t->link; 31 } 32 33 if(NULL==current) 34 return FALSE; 35 else 36 { 37 //把该节点删除,返回TRUE 38 m_del=current->link; 39 free(current); 40 *linkp=m_del; 41 } 42 return TRUE; 43 } 44 //需要形参为链表头指针的地址和要插入的值 45 int insert(Node **linkp,int new_value){ 46 register Node * current; 47 Node * m_new; 48 49 //寻找真确的插入位置,方法是按顺序访问链表,直到到达其值大于或等于新插入值的节点 50 while((current = *linkp)!=NULL && current->value < new_value) 51 { 52 linkp = ¤t->link; 53 } 54 //为新节点分配内存,并把新值存到新节点中,如果分配失败,返回FALSE 55 m_new =(Node*)malloc(LEN); 56 if(NULL==m_new) 57 return FALSE; 58 m_new->value = new_value; 59 //把新节点放入链表,返回TRUE 60 61 m_new->link = current; 62 *linkp=m_new; 63 64 return TRUE; 65 }
仅仅只需要将尾指针指向头节点,就可以构成单项循环链表,即tail->link=head;,有的时候,可能需要将链表逆置,当然,如果需要逆置,最好一开始就做双向链表。
1 Node * reverse(Node * head){ 2 Node * p,*q; 3 q= head; 4 p = head->link; 5 head = NULL; 6 while(p) 7 { 8 // 接到新链表里面去 9 q->link = head; 10 head = q; 11 // 继续遍历原来的链表 12 q = p; 13 p = p->link; 14 } 15 q->link = head; 16 head = q; 17 return head; 18 }
删除链表中所有值为x的节点,以及清除链表中重复的节点
1 // 功能: 删除链表中所有值为x的节点 2 // 形参: 1、若不带头结点,便是链表头指针的地址,即&head 3 // 2、若带头结点,便是链表头节点的next域的地址,即&head->next 4 // 形参: 为链表头指针的地址和要删除的值 5 void del_link(Node ** plink,int x){ 6 register Node * current; 7 while((current = *plink)!=NULL) 8 { 9 // 处理连续出现x的情况 10 while(current && current->data == x){ 11 // 保留指向下一个节点的指针 12 Node * temp = current; 13 * plink = current = current->next; 14 // 删除当前节点 15 free(temp); 16 } 17 18 //向下遍历链表 19 if (current) 20 { 21 plink = ¤t->next; 22 } 23 } 24 } 25 // 功能: 删除链表中重复多余的节点 26 // 形参: 1、若不带头结点,便是链表头指针的地址,即&head 27 // 2、若带头结点,便是链表头节点的next域的地址,即&head->next 28 void del_linkAll(Node ** plink){ 29 register Node * current; 30 while((current = *plink) != NULL){ 31 //注意,这里取指向下一个元素的指针的地址,这样删除是会保留这一个节点 32 del_link(¤t->next,current->data); 33 plink = ¤t->next; 34 } 35 }
对于双向链表,也就是在节点中再添加一个节点,让它与另一个指针指向的方向相反。当然,当节点有了两个节点之后,就可以构成更复杂的比如树图等复杂结构了,双向链表可像如下定义
1 #ifndef __LINKLISTEX_H__ 2 #define __LINKLISTEX_H__ 3 #include <string> 4 using std::string; 5 //================双向链表的定义=============== 6 template<class T> 7 class DulLinkList 8 { 9 private: 10 typedef struct DulNode{ 11 struct DulNode * prior; 12 T data; 13 struct DulNode * next; 14 }DulNode; 15 DulNode * frist; 16 void Init(); 17 void Del(DulNode * delNode); 18 public: 19 DulLinkList(); 20 ~DulLinkList(); 21 void AddElem(const T & data); 22 void DelElem(const T & data); 23 string ToString()const; 24 protected: 25 }; 26 #endif//__LINKLISTEX_H__
对双向链表的操作也无外乎增删改
1 #include "LinkListEx.h" 2 #include <iostream> 3 using namespace std; 4 5 template<class T> 6 DulLinkList<T>::DulLinkList(){ 7 Init(); 8 } 9 10 template<class T> 11 void DulLinkList<T>::Init(){ 12 // 初始化第一个结点 13 this->frist = new DulNode; 14 this->frist->prior = NULL; 15 this->frist->next = NULL; 16 } 17 18 template<class T> 19 void DulLinkList<T>::AddElem(const T & data){ 20 // 直接头部插入节点 21 DulNode * newNode = new DulNode; 22 newNode->data = data; 23 newNode->next = this->frist; 24 newNode->prior = NULL; 25 this->frist->prior = newNode; 26 this->frist = newNode; 27 } 28 29 30 template<class T> 31 void DulLinkList<T>::DelElem(const T & data){ 32 DulNode * current = this->frist->next; 33 while (current != NULL && current->data != data) { 34 current = current->next; 35 } 36 if (!current) 37 { 38 return; 39 } 40 Del(current); 41 } 42 43 template<class T> 44 void DulLinkList<T>::Del(DulNode * delNode){ 45 // 调整当前节点两端的节点的指针 46 delNode->prior->next = delNode->next; 47 delNode->next->prior = delNode->prior; 48 delete delNode; 49 } 50 template<class T> 51 DulLinkList<T>::~DulLinkList(){ 52 DulNode * current = this->frist; 53 while (current) 54 { 55 DulNode * old = current; 56 current = current->next; 57 delete old; 58 } 59 } 60 61 template<class T> 62 string DulLinkList<T>::ToString()const{ 63 string res; 64 DulNode * current = this->frist->next; 65 while (current) 66 { 67 res.append(1,current->data); 68 current = current->next; 69 } 70 return res; 71 }
链表是个很基础的东西,后面一些复杂的算法或数据结构的本质也是一个链表。链表和顺序表(也就是数组)都可以再进一步抽象成更复杂的数据结构。
比如队列和栈,不过是在链表或顺序表的基础上限制单端操作而已。再比如,由链表和顺序表还可以构成二叉树堆,它们还可以组合使用构成邻接表,十字链表,邻接多重表等结构用来描述图,等等。
字符串相关算法
做里快两年web开发了,可以说字符串是用多最多的数据类型了,所以针对字符串的算法也非常的多。先从简单的慢慢来。
首先最基本的是对字符串的求长,连接,比较,复制等
1 // 统计字符串长度 2 int str_len(char *str){ 3 return *str ? str_len(str+1)+1 : 0 ; 4 } 5 // 字符串复制 6 void str_cpy(char *str1,char *str2){ 7 while(*str1++ = *str2++); //当str2指向' '时,赋值给*str1 表达式的值为0 即为假。退出循环 8 //if(*str1 == ' ') // 考虑到 串2的长度大于串1的长度,防止指针越界 9 //break; 10 } 11 // 字符串比较 12 int str_cmp(char *str1,char *str2){ 13 int i;// i指向字符不同时数组下标 14 for(i=0;str1[i]==str2[i] && str1[i]!='