第一类:链表的考察(链表的插入,删除,排序和逆转等)
来源:互联网 发布:上古世纪帅哥捏脸数据 编辑:程序博客网 时间:2024/05/06 09:17
数据的存储结构在计算机中主要有四种基本的存储方式:顺序存储、链接存储、索引存储、散列存储方式。我们知道,顺序存储的优点是支持随机访问结构中的数据,但是在插入和删除方面运算时会造成大量数据的移动,效率较低;而链接存储却有效的补充了顺序存储的不足,当需要频繁的插入和删除时,效率得到提高。而索引存储附件了索引表,在访问时通过索引项(由关键字和地址组成值对)去访问数据的存储地址,而散列存储的就是hash的存储方式,即根据关键字通过hash转换求的数据的存储地址。在面试的过程中,链表是其中重要考察内容,下面让我们来一起学习和交流常见的链表操作。
首先,让我们重温一下单链表的数据结构:
typedef int datatype;typedef struct ListNode{ datatype data;//结点数据域 ListNode *next;//结点指针域}ListNode,*Linklist;
一、在单链表的实现的基本运算操作
这些基本操作包括:1.查找单链表中的第i个结点 2.返回指定元素的索引号 3.单链表的插入和删除,这些都是最基本的操作,大家一定要熟练,直接上码图!
* *author:xuzhaohufuncton:单链表的数据结构,查找、插入和删除 */#include <iostream>using namespace std;typedef int datatype;typedef struct node{datatype data;struct node *next;}ListNode,*LinkList;//查找单链表中的第i个节点的地址ListNode * Locate(LinkList head,int i){ListNode *p;int index = 0;if(head==NULL) return NULL;if(i<0) return NULL;p = head;if(p!=NULL && index<i){p=p->next;index++;}return p;}//返回链表中第一个节点元素为 x 的值的索引号int findValue(LinkList head,datatype x){ListNode *p;int index = 1;if(head==NULL) return 0;p=head;if(p!=NULL){if(p->data == x) return index;else{p=p->next;index++;}}else{cout<<"单链表中没有这个值的元素"<<endl;return 0;}}//单链表的插入 分表首插入和表中插入void InsertNode(LinkList &head,int i,datatype x){ListNode *p,*q;p = Locate(head,i-1);//注意是掺入前面的一个元素q = new ListNode;q->data = x;if(i == 0){q->next = head;head = q;}else{q = p->next;p->next = q;}}//单链表的删除 ,也分表头删除和表中删除void DeleteNode(LinkList &head,int i){ListNode *p,*q;//q是删除节点p是其前一个节点p = Locate(head ,i-1);//注意是找到前面一个元素if(i==0){q = head;head=q->next;delete q;}else{if(p==NULL)//i值给的有问题,索引值溢出后者为负值cout<<"error"<<endl; else if(p->next == NULL)//p恰好是最后一个元素 cout<<"no ith node"<<endl;else{q = p->next;p->next = q->next;delete q;}}}int main(){return 0;}
二、用链表实现对栈和队列
这是个基础也是非常重要的算法实现问题,既能考察对栈和队列的理解又考察了对链表的操作,因此,也是面试中应该着重学习的地方。
2.1 链栈的数据操作
/** * author:xuzhaohu * function:stackNode 先进后出 * date: */#include<iostream>using namespace std;//与单链表相似,不同之处在与插入和删除只限定在表首进行,表头指针就是栈顶元素 typedef int datatype;typedef struct node{datatype data;struct node *next;}StackNode,*LinkStack;// 链栈的插入 void push(LinkStack &top,datatype x){StackNode *p;p = new StackNode;//注意:链栈的插入只考虑单链表的表首插入 p->data = x;p->next = top;top = p;}//链栈的弹出 void pop(LinkStack &top,datatype &x){StackNode *p;if(top == NULL)cout<<"underflow"<<endl;else{//链栈的删除只考虑表首的删除 p = top;x = top->data;top = top->next;delete p;}}//读取链栈的栈顶元素 void GetTop(LinkStack top, datatype &x){if(top == NULL) cout<<"error";else x = top->data;}//置空链栈 void ClearStack(LinkStack &top){top = NULL;}//判断链栈是否为空 int StackEmpty(LinkStack &top){if(top == NULL) return 1;else return 0;}int main(){return 0;}
2.2链队列的数据操作
/** *author:xuzh *function:链队列的数据结构,先进先出 */#include<iostream>using namespace std;typedef int datatype;typedef struct node{datatype data;struct node *next;}QueueNode;typedef struct{QueueNode *front;//队头指针QueueNode *rear;//队尾指针}LinkQueue;QueueNode *p,*q;LinkQueue QU;datatype x;//链队列的插入,只能在队尾插入void EnQueue(LinkQueue &QU,datatype x){QueueNode *p = new QueueNode;p->data = x;p->next = NULL;//p为最后一个元素if(QU.front == NULL) QU.front = QU.rear = p;else{QU.rear->next = p;//队尾元素变为新的元素p,p为旧的队尾元素的下一个元素QU.rear = p;}}//链队列的删除,只能在队首操作void DeQueue(LinkQueue &QU,datatype &x){QueueNode *q;if(QU.front == NULL) cout<<"underflow"<<endl;else{q = QU.front;x = q->data;QU.front = q->next;delete q;}}//读栈头元素void GetFront(LinkQueue &QU,datatype &x){if(QU.front == NULL) cout<<"error"<<endl;else x = QU.front->data;}//清空队列void ClearQueue(LinkQueue &QU){QU.front = QU.rear = NULL;}//判定一个队列是否为空int QueueEmpty(LinkQueue &QU){if(QU.front == NULL) return 1;else return 0;}int main(){return 0;}
三、链表的综合操作
3.1.逆向链表的实现 ReverseList(ListNode &head)
思路:通过改变指针指向实现,代码如下:
//reverse the listvoid ReverseList(LinkList &head){ListNode *p,*q,*r;//相邻的两个指针if(head == NULL) cout<<"error"<<endl;p = head;q = p->next;p->next = NULL;//首节点对应着 逆转后的 最后一个节点while(q!=NULL){if(q->next==NULL)head = q;//表首指针指向最后一个元素r = q->next;q->next = p;p = q;q = r;}}
3.2尽量用最小的时间消耗完成对中间结点的查询
思路:用快慢指针实现,快指针步长为2,慢指针步长为1,同时遍历,当快指针遍历完成时,慢指针指向就是中间结点,复杂度为O(n),代码如下
//尽量用最小的时间消耗完成对中间结点的查询void FindMindleNode(LinkList head){ListNode *fast,*slow;//定义一个快慢指针,一个步长为2,一个步长为1int index = 1;//中间节点的索引值if(head == NULL){ cout<<"error"<<endl; return ;}slow = fast = head;if(head->next == NULL){ cout<<"the mid node is "<<index<<endl; return ;} slow = slow->next;//慢指针走一步fast = fast->next;//快指针走两步while(fast!=NULL && slow!=NULL){index++;slow = slow->next;if(fast->next == NULL)//如果fast的下一个指针就已经为空了,说明快指针已经遍历完成fast = fast->next;//这时候让fast指针指向最后一个元素就行elsefast = fast->next->next;}cout<<"the mid node is "<<index<<endl;}
3.3用最小空间和时间找出该链表的倒数第m个元素
思路:同样可以采用双指针的,一个指针先遍历m个元素,然后第二个指针与第一个指针同时遍历链表,直到第一个指针遍历结束,则第二个指针遍历到的位置即为倒数第m个元素。代码如下
//get the mth element in the listint GetLastM(LinkList head, int m){ListNode *fast,*slow;int i = 0;fast = slow = head;if(head == NULL) return -1;while(fast!=NULL){i++;fast = fast->next;if(i>=m){if(slow!=NULL) slow = slow->next;}}return slow->data;}
3.4如何判断一个单向链表是否存在循环
思路:一、使用步长法判断,用不同步长遍历两次,看是否遇见。遇见则证明有环;二、如果链表中当前的node的下一个node不是前面的任何一个访问后的node,那么则没有环,否则有环。下面是思路一的代码
// Circle List 's last element->next = headbool CircleList(LinkList head){//define two different step pointer,if they meet,there is circle, or notListNode *fast,*slow;if(head == NULL) return false; slow = head;fast = head->next;while(fast!=NULL && fast->next!=NULL && slow!=fast){slow = slow->next;fast = fast->next->next;}if(slow = fast) return true;else return 0;}
结束!小弟也在学习中,希望通过自己学到的和大家进行交流,如有不准确和正确的地方,请各位指正,小弟不甚感激!!^_^
- 第一类:链表的考察(链表的插入,删除,排序和逆转等)
- 链表的插入、删除、排序、追加等源码
- 揭开链表逆转和排序的面纱
- C++ 链表的递归逆转和循环逆转
- 链表的逆转
- 链表的逆转
- 链表的创建、插入、删除、排序和逆置
- C++链表的创建、插入、删除、查找、合并、排序、修改等操作的实现
- 链表的插入 删除 排序 倒叙
- 链表的删除,插入,查找,排序
- C语言中,链表的创建,插入,删除,遍历,求链表长度,排序等
- 数据结构链表的操作集合(建立,遍历,插入,删除,排序,长度,空判断等)
- 链表的基本操作(插入,删除,排序、逆置等)
- 单链表的插入删除以及逆转
- 保留主表,删除一类表的索引和约束
- 基本链表的逆转
- 算法:链表的逆转
- //链表的原地逆转
- 是什么让你的ExtJS应用程序运行缓慢?
- java克隆(深浅拷贝,复制)详解
- Wooden Stichs(P1065)
- linux svn工作空间锁定无法更新的解决方法(Working copy '.' locked)
- 两个样本的Student's t-test (1)
- 第一类:链表的考察(链表的插入,删除,排序和逆转等)
- excel 导出
- 两个样本的Student's t-test (2)
- C#字段为什么用属性封装?
- 华为的一道面试题的解答(自己的另解)
- Lisp学习笔记1——打印素数
- 【HTML5】3D模型--百行代码实现旋转立体魔方
- 集合框架之vector取值方式
- 集合框架之LinkedList方法使用