1.链表逆序输出
必然需要遍历,并且只知道头指针,并且不破坏源链表结构;既然逆序,那么容易想到后进先出,很容易的想到堆栈;
堆栈的基本操作:
std::stack<int>value;
value.push(parameter);
value.top()
value.pop();
或者采用这种方法,Head->Node1->Node2->Node3->....->NodeN;
第一次交换节点1和节点2,变成,Head->Node2->Node1->Node3->....->NodeN;
第二次交换节点2和节点3,变成,Head->Node3->Node2->Node0->....->NodeN;
.......
struct Node *p2 = Head->next;
while(p2->next !=NULL){
struct Node *q = p2->next;
p2->next = q->next;
q->next=Head->next;
Head->next = q;
}
2.O(1)时间内删除链表
如果给定一个链表的头指针和指向一个节点的指针,要求删除该节点指针指向的节点;
一般而言,如果要删除一个节点,我们需要找到该节点的上一个节点,使该节点的上一个节点的指针,指向该节点的下一个节点;
而如果按照这种思想,必须遍历;
换种思路,其实不需要遍历;
如下图:需要删除i节点,
我们可以将其后的j节点的值赋给i节点,之后i的指针指向j的后面的节点;
(i位于结尾,或者链表只含有一个节点,需要特殊处理)
3.链表的倒数第K个节点
可以使用两个指针,一个指向链表头,一个指向距离链表头节点k-1的节点;同时后移,当第二个指针到达尾部,第一个指针所指即为所指;
4.链表逆序
5.合并两个排序的链表
6.两个链表的第一个公共节点
如果两个链表有节点重合,那么它们的拓扑一定是Y形状的,而不可能是X形状的。
两种方法,一种是使用两个栈,遍历,将两个链表的元素入栈,然后依次出栈,遇到第一个不相同的节点,返回;
一种是,首先遍历两个链表,设置两个指针,将较长的链表先提前走两个链表的差值,之后一起向后遍历,遇到第一个相同的节点返回;
7.链表操作注意点
链表末尾指针记得赋空值;
8.快排
static void quick_sort1(int s[], int l, int r) {
if (l < r) {
int i = AdjustArray(s, l, r);// 先成挖坑填数法调整s[]
quick_sort1(s, l, i - 1); // 递归调用
quick_sort1(s, i + 1, r);
}
}
static int AdjustArray(int array[], int left, int right) // 返回调整后基准数的位置
{
int flagNum = array[left]; // s[l]即s[i]就是第一个坑
while (left < right) {
// 从右向左找小于x的数来填s[i]
while (left < right && array[right] >= flagNum)
right--;
if (left < right) { //注意这里,必须加判断,才能确保是因为 前面条件 s[j] >= x 不成立,才跳出while循环的。
array[left] = array[right]; // 将array[right]填到array[left]中,array[right]就形成了一个新的坑
left++; //注意这里为什么是 i++, 而不是 j--; 因为i马上会移到下一个位置,而j需要保持现在的位置,记录交换之后的位置;
}
// 从左向右找大于或等于x的数来填s[j]
while (left < right && array[left] < flagNum)
left++;
if (left < right) {
array[right] = array[left]; // 将s[i]填到s[j]中,s[i]就形成了一个新的坑
right--;
}
}
// 退出时,i等于j。将x填到这个坑中。
array[left] = flagNum;
return left;
}
9.归并排序
static void mergeSort(int array[], int left, int right, int temp[]){
if (left < right){ //
int middle = (left + right)/2;
mergeSort(array, left, middle, temp);
mergeSort(array, middle + 1, right, temp);
merge(array, left, middle, right, temp);
}
}
static void merge(int array[], int left, int middle, int right, int temp[]){
int i = left, j = middle;
int l = middle + 1, m = right;
int k = 0;
while (i <= j && l <= m){
if(array[i] >= array[l])
temp[k++] = array[l++];
else
temp[k++] = array[i++];
}
while(i <= j) //
temp[k++] = array[i++];
while(l <= m)//
temp[k++] = array[l++];
for (i = 0; i < k; i++){
array[left + i] = temp[i];
}
}
10.二分查找
static boolean search(int array[], int left, int right, int value){
if (left <= right){
int middle = (left + right)/2;
if (array[middle] == value)
return true;
else if(array[middle] > value)
return search(array, left, middle - 1,value);
else
return search(array, middle + 1, right,value);
}
return false;
}
11.连续子数组最大值
static int maxSummary(int array[], int length){
int max = 0;
int current = 0;
for(int i = 0; i < length; i++){
current = current + array[i];
if(current <= array[i])
current = array[i];
if(current < current - array[i]){
max = current - array[i];
}
}
return max;
}
分析:时间复杂度O(n),意味着只需要遍历一次,不能使用枚举法
思想,例,1,-2,3,10,-4,7,2,-5;首先把1放到当前总和中,current为1;
之后把-2加到current中,current为-1,-1小于原先的current :1,因此当前的max为:1
再把3加入current,current为2, 2小于当前值3,因此,将current记为当前值,3;
再把10加入到current,current为13;
再把-4加入到current,current为9,9小于原先的13,因此max为13,;
。。
12. 调整数组中奇数偶数的位置,使奇数位于偶数之前。
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
adjustArray(array);
}
public static void adjustArray(int[] array){
int length = array.length;
int left = 0;
int right = length - 1;
int temp = 0;
while(left < right){
while(left < right){
if(array[right]%2 != 0)
break;
else
right--;
}
while(left < right){
if(array[left]%2 == 0)
break;
else
left++;
}
temp = array[right];
array[right] = array[left];
array[left] = temp;
left++;
right--;
}
for(int i = 0;i < array.length;i++)
System.out.println(array[i]);
}