反转单链表 和 将数组按照某种条件分为前后两个部分

来源:互联网 发布:鼎复数据 知乎 编辑:程序博客网 时间:2024/04/30 07:59

what did not kill you, make you stronger! 今天下午终于完结这几日笼在心头的乌云,彻底打败! 之前读到<剑指offer>第三章的"反转链表的题目", 当时决定顺带复习国庆放假前的数据结构啥的,于是打算by my own head,不借助书本的来完成, 困难是有的,算法卡壳了,在座位上苦苦思不得,注意力很难集中时,真的想放弃。又比方说C++语法好像都忘了,这些都不是问题,当决定放弃时才是问题。

现在开始总结:

首先上的是代码问题,之后再对指针的操作做总结。

一,代码问题

1.单链表实现(最简单的模式,链表不排序,从表头开始插入新元素)

2.反转单链表

#include <iostream>using namespace std;//本来想写成函数模板的,不过想来模板形式简单,但是需要写的内容较多,容易出错误,这已经领教过了class list{public:list() {listHead = NULL;}            //必须初始化单链表的头指针listHead, vs会给没有初始化的指针分配0XCCCCCCCC,而不是0X00000000(NULL)。        void addNode(int a);void rotateList();void print();private:class listNode{public:listNode(int a, listNode *p):m_value(a),m_pNext(p) {}int m_value;listNode *m_pNext;};listNode *listHead;                             //finally I FIND the errro!!!!!!!!!!!!!!!!!!!};void list::addNode(int a)  //借助的是树的生成的思想{if(listHead == NULL)listHead = new listNode(a, NULL);    // listNode *listHead = new listNode(a, NULL);  这里也是一个致命伤,这样是定义了一个临时变量else{listNode *pNew = new listNode(a, listHead);listHead = pNew;}}//在反转单链表初始时,在使用循环还是递归时有些纠结,不过再纠结都不如切实的写代码解决问题更加有效。void list::rotateList(){listNode *p = listHead->m_pNext;listNode *q = p->m_pNext;listNode * pre = NULL;p->m_pNext = listHead;listHead->m_pNext = NULL;  //这句话不写有一个循环指代        //while内的条件总是那么需要人一再去确定//复杂的指针操作来了        while(q->m_pNext)            //while(p->m_pNext)     {pre = p;p = q; q = p->m_pNext;p->m_pNext = pre; } q->m_pNext = p;        //指针认识更上一层楼。 无论是 p, q 还是头指针listHead 都是指针,这里真正的实物是 new listNode(  , )时。所以不要牵挂//listHead 此时会指向q所指向的位置,而去操心listHead之前指的那个节点会受到影响。因为节点之间的关联是通过指针完成,一旦关        //联之后,指针就free to go to whatever it wants.        listHead = q;    //listHead = p;  错误的代码输出时丢失了链表的第一个元素。}//打印链表void list::print(){listNode *i = listHead;while(i!=NULL){ cout<<i->m_value<<'\t'; i = i->m_pNext;} cout<<endl;}void main(){list ll;ll.addNode(1);ll.addNode(2);ll.addNode(3);ll.addNode(4);ll.addNode(5);ll.addNode(6);ll.addNode(7);ll.addNode(8);ll.print();cout<<"..............................."<<endl;  //分割线ll.rotateList();ll.print();}

总结:1 定义指针之后,必须初始化,否则系统给你初始化,让你对指针判断是否为NULL时出错。

二、 将数组以某种条件分成两个部分

最初遇到的问题同样来自《剑指offer》中将一组整数(有奇数有偶数)中奇数放在数组的前面,偶数放在后面,要求只遍历一次数组。

好吧一看到这个题目,立马联想起快速排序的思路,好吧,自虐的路又开始了:先写这个程序,又写快速排序by my own hand write it,后来回忆被虐得不轻,快排的那个递归就

让哥崩溃的,在写树的时候,递归写的就艰难,好长时间来这个,在楼道外狠狠转了一圈还是写了出来。


////明天需要对比快排,再复习一遍//#include <iostream>using namespace std;//void swap(int &a, int &b){//第一次写错了//int tmp;//tmp = a;//a = b;//b = a;int tmp;tmp = a;a = b;b = tmp;}//////这个函数本质上都是把一个数组分成两个部分,这里的算法借用了 快速排序 的思想//void odd_even(int a[], int length)//{//int s = -1;////for(int i=0; i<length; i++)//{//if(a[i]%2)//s++;//if(i != s  && (a[i]%2) )    //if(i != s ) 开始是这样写的//swap(a[i],a[s]);//}////}////void main()//{////int a[] = {1,2,33,5,67,8,8,8};//int a[] = {1,2,3,4,5,6,7,8};//int length = sizeof(a)/sizeof(a[0]);////odd_even(a, length);////for(int i=0; i<length; i++)//cout<<a[i]<<endl;//}//write kuaipai by your own hand//针对数组a[i] 的排序//这个函数的递归写的极具递归的典型结构//先写边界条件,然后对当前层进行操作,然后递归调用下一层void kp(int a[], int first, int pivot){        //边界条件if(first > pivot)return;if(first == pivot)return;               //对当前层进行操作int s = first - 1;  for(int i=first; i<pivot; i++){//if(a[first] < a[pivot])//s++;//if( (a[first]<a[pivot])// && (s!=i) )// swap(a[s], a[i]);                                if(a[i] < a[pivot])s++;       //s指向第一个偶数if( (a[i]<a[pivot]) && (s!=i) ) swap(a[s], a[i]);}swap(a[pivot], a[++s]);                <pre name="code" class="cpp">        //递归调用下一层
 kp(a, first, s-1);kp(a, s+1, pivot);}void kuaipai(int a[], int length){int pivot = length - 1;kp(a, 0, pivot);}void main(){int a[] = {1,7,8,9,2,4,6,5};int length = sizeof(a)/sizeof(a[0]);kuaipai(a, length);for(int i=0; i<length; i++)cout<<a[i]<<'\t';}







0 0
原创粉丝点击