考研数据结构代码题

day01

//Day01
//在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一
//编写算法以实现上述操作
int delete(LinkList &L,int x)
{
    if(L == nullptr || L->next == nullptr){
        return 0;
    }
    LinkList p = L->next;
    LinkList prev = L;
    while(p != nullptr){
        if(p->data == x){
            prev->next = p->next;
            delete p;
            p = prev->next;
        }else{
            prev = p;
            p = p->next;
        }   
    }
}

代码解释:

  1. 初始化指针

    • p 指向链表的第一个节点(L->next)。

    • prev 指向链表的头结点(L),用于记录当前节点的前一个节点。

  2. 遍历链表

    • 使用 while 循环遍历链表,直到 p 为 nullptr

  3. 删除节点

    • 如果 p->data == x,则删除当前节点 p

      • 将 prev->next 指向 p->next,跳过 p

      • 释放 p 的内存。

      • 更新 p 为 prev->next,继续检查下一个节点。

    • 如果 p->data != x,则更新 prev 和 p 指针,继续遍历。

注意事项:

  • 该函数假设链表是带头结点的单链表。

  • 删除节点时,需要确保 prev 指针正确地指向当前节点的前一个节点。

  • 删除节点后,需要更新 p 指针,以继续遍历链表。

  • 带头节点的单链表表示为:

  • L -> [head] -> [1] -> [2] -> [3] -> [2] -> [4] -> [2] -> [5] -> nullptr
    prev       p

 day02

//day02
// 将两个有序顺序表合并为一个新的有序顺序表
bool Merge(SqList A, SqList B, SqList &C) {
    if (A.length + B.length > MAX_SIZE) {
        return false; // 合并后的长度超过最大容量
    }

    int i =  0,j = 0,k = 0;
    while(i < A.length && j < B.length){
        if(A.data[i] <= B.data[j]){
            C.data[k] = A.data[i];
            k++;
            i++;
        }else{
            C.data[k] = B.data[j];
            k++;
            j++;
        }
    }
  1. 合并有序顺序表

    • while (i < A.length && j < B.length):当 A 和 B 都还有元素时,进行循环。

      • if (A.data[i] <= B.data[j]):如果 A 的当前元素小于等于 B 的当前元素,则将 A 的当前元素插入到 C 中,并移动 A 和 C 的指针。

      • else:否则,将 B 的当前元素插入到 C 中,并移动 B 和 C 的指针。

  2. 处理剩余元素

    • while (i < A.length):如果 A 还有剩余元素,将它们全部插入到 C 中。

    • while (j < B.length):如果 B 还有剩余元素,将它们全部插入到 C 中。

  3. 更新合并后的线性表长度

    • C.length = k;:更新 C 的长度为 k,即合并后的元素个数。

day03

//Day03
//设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)
void Reverse(SqList &L)
{
    int low = 0;
    int high = L.length-1;
    while(low < high){
        int temp = L.data[low];
        L.data[low] = L.data[high];
        L.data[high] = temp; 
        low++;
        high --;
    } 
}

要设计一个高效算法将顺序表 L 的所有元素逆置,并且要求算法的空间复杂度为 O(1),可以使用双指针法。具体步骤如下:

  1. 初始化两个指针:一个指向顺序表的头部(left),另一个指向顺序表的尾部(right)。

  2. 交换元素:交换 left 和 right 指向的元素,然后移动 left 指针向右,right 指针向左。

  3. 重复步骤2:直到 left 指针不再小于 right 指针。

day04

//Day04
//对长度为n的顺序表L,编写一个时间复杂度为O(n),空间复杂度为O(1)的算法,
//该算法删除线性表中所有值为x的数据元素
/*
分析:O(n)扫描一次顺序表;O(1)申请常数个辅助空间
*/
void Del_Sq(SqList &L,int x){
    if(L.length == 0){
        return;
    }

    int i = 0;
    int k = 0;
    while(i<L.length){
        if(L.data[i] == x){
            k++;
        }else{
            L.data[i-k] = L.data[i];
        }
        i++;
    }
    L.length = L.length-k;
}

  • 使用 while 循环遍历顺序表 L

  • 如果当前元素 L.data[i] 的值等于 x,则 k 增加 1,表示遇到一个需要删除的元素。

  • 如果当前元素 L.data[i] 的值不等于 x,则将该元素向前移动 k 个位置,即 L.data[i-k] = L.data[i]。这样可以保证所有不等于 x 的元素都向前移动,覆盖掉前面等于 x 的元素。

  • 时间复杂度:O(n),因为代码只遍历了一次顺序表。

  • 空间复杂度:O(1),因为只使用了常数个额外的变量 i 和 k

    //方法2
    void Del_Y(SqList &L,int x){
        int i = 0;
        int k = 0;
        if(L.length == 0){
            return;
        }
    
        while(i < L.length){
            if(L.data[i] != x){
                k++;
                L.data[k] = L.data[i];
            }
            i++;
        }
        L.length = k;
    }

  • i 是遍历顺序表的索引。

  • k 用于记录当前已经保留的元素个数。

  • 时间复杂度:O(n),因为代码只遍历了一次顺序表。

  • 空间复杂度:O(1),因为只使用了常数个额外的变量 i 和 k

day05

//Day05
//从顺序表中删除其值在给定值s与t之间(包含s和t,要求s < t)的所有元素
//如果s或t不合理或顺序表为空,则显示出错信息并退出运行
int Del_XY(SqList &L, int s, int t) {
    if (L.length == 0 || s >= t) {
        return -1; // 返回错误码
    }

    int k = 0;
    for (int i = 0; i < L.length; i++) {
        if (L.data[i] < s || L.data[i] > t) {
            L.data[k] = L.data[i];
            k++;
        }
    }
    L.length = k;
    return 1; // 返回成功码
}

day06

//Day06
//从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同
void Del_Same(SqList &L){
    if(L.length == 0){
        return;
    }

    int k = 0;//用于记录不重复元素的个数

    for(int i = 1; i < L.length; i++){
        if(L.data[i] != L.data[k]){
            k++;
            L.data[k] = L.data[i]; 
        }
    }
    L.length = k+1;
}
  • 使用 for 循环遍历顺序表 L,从第二个元素开始(即 i = 1)。

  • 如果当前元素 L.data[i] 的值不等于前一个不重复元素 L.data[k],则将该元素保留,并将其移动到 L.data[k] 的位置,然后 k 增加 1。

  • 如果当前元素 L.data[i] 的值等于前一个不重复元素 L.data[k],则跳过该元素,不进行任何操作。

  • 时间复杂度:O(n),因为代码只遍历了一次顺序表。

  • 空间复杂度:O(1),因为只使用了常数个额外的变量 i 和 k

day07


//Day07
/*已知一维数组A[M+N]中依次存放两个线性表
(a1,a2,a3,a4....an与b1,b2,b3...bn)
试写函数将两顺序表的位置互换,
即将b1,b2,b3...bn放在a1,a2,a3,a4....an前面*/
void Reverse(int arr[], int start,int end){
    while(start < end){
        swap(arr[start],arr[end]);
        start++;
        end--;
    }
}

void SwapSequence(int arr[], int M, int N){
    Reverse(arr, 0, M+N-1);
    Reverse(arr, 0, N-1);
    Reverse(arr, N, M+N-1);
}

day08

//Day08
//2010统考真题
//算法思想:先将前p个元素逆置,然后将后n-p个元素逆置,最后将整个顺序表逆置
void Reverse(int arr[], int start, int end) {
    while (start < end) {
        swap(arr[start], arr[end]);
        start++;
        end--;
    }
}

void SwapSequence(int arr[], int length, int p) {
    Reverse(arr, 0, p - 1);
    Reverse(arr, p, length - 1);
    Reverse(arr, 0, length - 1);
}
  • 时间复杂度:O(n),因为每个逆置操作的时间复杂度为 O(n),而总共进行了三次逆置操作。

  • 空间复杂度:O(1),因为只使用了常数个额外的变量。

day09

// Day09
// 试编写带头结点的的单链表L中删除一个最小值结点的高效算法(假设最小值结点是唯一的)
void Del_Min(LinkList &L) {
    if (L == nullptr || L->next == nullptr) {
        return;
    }

    LinkList minpre = L; // 最小值结点的前驱结点
    LinkList min = L->next; // 最小值结点
    LinkList prev = L; // 当前结点的前驱结点
    LinkList p = L->next; // 当前结点

    while (p != nullptr) {
        if (p->data < min->data) {
            min = p;
            minpre = prev;
        }
        prev = p;
        p = p->next;
    }

    minpre->next = min->next;
    delete min;
}

  • minpre:用于记录最小值结点的前驱结点。

  • min:用于记录最小值结点。

  • prev:用于记录当前结点的前驱结点。

  • p:用于遍历链表的当前结点。

  • 使用 while 循环遍历链表 L,从第一个结点开始(即 L->next)。

  • 如果当前结点 p 的值小于当前最小值结点 min 的值,则更新 min 和 minpre

  • 更新 prev 为当前结点 p,并将 p 指向下一个结点。

  • 时间复杂度:O(n),因为需要遍历整个链表一次来找到最小值结点。

  • 空间复杂度:O(1),因为只使用了常数个额外的指针变量。

day10

//Day10
//使用头插法建立单链表
void List_HeadInsert(LinkList &L,int n){
    L = new Lnode;
    L->next = nullptr; //创建头结点

    for(int i = 0; i < n; i++){
        LinkList p = new Lnode;
        cout<<"请输入插入节点的数据域:";
        cin>>p->data;
        cout<<endl;
        p->next = L->next;
        L->next = p;
    }
}

day11

//Day11
//使用尾插法建立单链表
void List_TailInsert(LinkList &L,int n){
    L = new Lnode;
    L->next = nullptr;
    LinkList r = L;//尾指针r指向头结点

    for(int i = 0; i < n; i++){
        LinkList p = new Lnode;
        cout<<"请输入新节点的数据域:";
        cin>>p->data;
        cout<<endl;
        r->next = p;
        r = p;

    }

}

day12

//Day12
//试编写算法将带头结点的单链表就地逆置,
//所谓的“就地”是指辅助空间的复杂度为O (1)
LinkList Reverse_List(LinkList &L){
    LinkList p, r;
    p = L->next;
    L->next = nullptr;

    while(p != nullptr){
        r = p->next;
        p->next = L->next;
        L->next = p;
        p = r;
    }
    return L;
}

这里将p指向链表的第一个实际节点,并将头结点的next指针置为NULL,表示链表为空。

这个循环实现了链表的就地逆置。具体步骤如下:

  • 保存p的后继结点r,以便在逆置后继续遍历链表。

  • pnext指针指向当前头结点的next,即p成为新的第一个节点。

  • 将头结点的next指向p,完成逆置操作。

  • p指向下一个节点r,继续遍历链表。

假设你有一个带头结点的链表,初始状态如下:

L -> [头结点] -> [1] -> [2] -> [3] -> NULL

经过逆置后,链表的状态将变为:

L -> [头结点] -> [3] -> [2] -> [1] -> NULL

day13

//Day13
//设在一个带表头结点的单链表中所有元素的结点的数据值无序,试编写一个函数,
//删除表中所有介于给定的的两个值(作为函数的参数给出)之间的元素的元素(若存在)。
void Del_XY(LinkList &L,int x, int y){
    if(L = nullptr || L->next = nullptr){
        return; //空链表或只有一个头结点无需删除
    }

    LinkList p = L->next;//当前结点
    LinkList prev = L; // 前一个结点
    while(p->next !=nullptr){
        if(p->data < x && p->data < y){
            prev->next = p->next;
            delete p;
            p = prev->next;
        }else{
            prev = p;
            p = p->next;

        }
    }
}

day14


//Day14(上)
//给定两个单链表,编写算法找出两个单链表的公共结点
LinkList search_common(LinkList &LA,linkList &LB){
	LNode *p = LA->next;
	LNode *q = LB->next;
	while(p){
		while(q){
			if(p == q){
				return p;
			} else {
				q = q->next;
			}
		}
		p = p->next;
		q = LB->next;//将q指针初始化到头结点的下一个结点
	}
	return NULL;//找不到就返回虚无
}
//时间复杂度:O(lenA * lenB)
 
//Day14(下)
//给定两个单链表,编写算法找出两个单链表的公共结点(优化算法)
LinkList search_common(LinkList &LA,LinkList &LB){
	LNode *p,*q;	
	int k;
	int lenA = length(LA);//求出链表长度
	int lenB = length(LB);
	if(lenA-lenB > 0){
		k = lenA - lenB;//求出链表的长度差
		p = LA->next;
		q = LB->next; 
	} else {
		k = lenB - lenA;
		p = LB->next;
		q = LA->next;
	}
	while(k--){
		p = p->next;//p先移动k个位置
	}
	while(p!=NULL){
		if(p == q){//若p==q,则找到公共结点
			return p;
		} else {
			p = p->next;//若不等,同步向后移动,可以同时到达表尾
			q = q->next;
		}
	}
	return NULL;//没有公共结点
}
//时间复杂度:O(max(lenA,lenB));

day15

//Day15
//将一个带头结点的单链表A分解为两个带头结点的单链表A和B,
//使得A表中含有原表中序号为奇数的元素,
//而B表中含有原表中序号为偶数的元素,且保持其相对顺序不变

LinkList DisCreate_L(LinkList &A){
    LinkList B = new Lnode;
    B->next = nullptr; //初始化单链表B
    LinkList a = A;
    LinkList b = B;
    LinkList p = A->next;   //原A链表第一个结点
    A->next = NULL;         
    int i = 0;
    while(p != nullptr){
        i++;
        if(i%2 == 0){ // 偶数
            b->next = p;
            b = p;
        }else{
            a->next = p;
            a = p;
        }
        p = p->next;
    }
    a->next = nullptr;
    b->next = nullptr;
    return B;

}
  • a 指向链表 A 的头结点。

  • b 指向链表 B 的头结点。

  • p 指向原链表 A 的第一个实际节点。

  • 将链表 A 的头结点的 next 指针置为 nullptr,表示链表 A 为空。

  • 使用计数器 i 记录当前节点的序号。

  • 如果当前节点的序号为偶数,则将该节点插入到链表 B 的尾部,并更新 b 指针。

  • 如果当前节点的序号为奇数,则将该节点插入到链表 A 的尾部,并更新 a 指针。

  • p 指向下一个节点,继续遍历。

  • 将链表 A 的最后一个节点的 next 指针置为 nullptr,表示链表 A 的结束。

  • 将链表 B 的最后一个节点的 next 指针置为 nullptr,表示链表 B 的结束

day16

//Day16
//设C={a1,b1,a2,b2,...an,bn}为线性表,采用带头结点的hc单链表存放,
//设计一个就地算法,将其拆分为两个线性表,
//使得A={a1,a2,..., an},B={ bn,...,b2,b1}
LinkList Discreate(LinkList &C,LinkList &A, LinkList &B){
    A = new Lnode;
    A->next = nullptr;
    B = new Lnode;
    B->next = nullptr;
    LinkList p = C->next;
    C->next = nullptr;
    LinkList ra = A;
    LinkList rb;

    while(p != nullptr){
        ra->next = p;
        ra = p;
        p = p->next;
        if(p){
            rb = p->next;
            p->next = B->next;
            B->next = p;
            p = rb;

        }
    }
    ra->next = nullptr;
    return A,B;
}

详细步骤

  1. 初始化链表 A 和 B

    • A = new Lnode;:创建链表 A 的头结点。

    • A->next = nullptr;:将链表 A 的头结点的 next 指针设置为 nullptr

    • B = new Lnode;:创建链表 B 的头结点。

    • B->next = nullptr;:将链表 B 的头结点的 next 指针设置为 nullptr

  2. 初始化指针

    • LinkList p = C->next;:将指针 p 指向链表 C 的第一个元素。

    • C->next = nullptr;:断开链表 C 的头结点,使其成为一个空链表。

    • LinkList ra = A;:将指针 ra 指向链表 A 的头结点,用于构建链表 A

    • LinkList rb;:声明指针 rb,用于构建链表 B

  3. 遍历链表 C

    • while (p != nullptr):当 p 不为 nullptr 时,继续遍历链表 C

  4. 插入链表 A

    • ra->next = p;:将 p 插入到链表 A 的末尾。

    • ra = p;:将 ra 指向链表 A 的最后一个节点。

    • p = p->next;:将 p 指向下一个节点。

  5. 插入链表 B

    • if (p != nullptr):检查 p 是否为 nullptr,确保还有下一个节点可以插入到链表 B

    • rb = p->next;:保存 p 的下一个节点。

    • p->next = B->next;:将 p 插入到链表 B 的头部。

    • B->next = p;:更新链表 B 的头指针。

    • p = rb;:将 p 指向下一个节点。

  6. 断开链表 A 的最后一个节点

    • ra->next = nullptr;:确保链表 A 的最后一个节点的 next 指针为 nullptr

  7. 返回链表 A 和 B

    • return A, B;:返回链表 A 和 B

day17

//Day17
//在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,
//设计算法去掉数值相同的元素,使表中不再有重复的元素,
//例如 (7,10,10,21,30,42,42,42,51,70)将变成(7,10,21,30,42,51,70)
void Del_same(LinkList &L){
    LinkList pre = L->next;
    LinkList p = pre->next;

    while(p != nullptr){
        if(pre->data == p->data){
            pre->next = p->next;
            delete p;
        }
        pre = pre->next;
        p = p->next;
    }
}

  1. 初始化指针

    • LinkList pre = L->next;:将指针 pre 指向链表的第一个节点。

    • LinkList p = pre->next;:将指针 p 指向链表的第二个节点。

day18

// 归并两个递增链表为一个递减链表
LinkList Merge(LinkList &A, LinkList &B) {
    LinkList C = new Lnode;  // 创建归并后的链表 C 的头结点
    C->next = nullptr;

    LinkList a = A->next;  // a 指向链表 A 的第一个节点
    LinkList b = B->next;  // b 指向链表 B 的第一个节点
    LinkList r;  // 用于保存下一个节点的指针

    while (a != nullptr && b != nullptr) {
        if (a->data < b->data) {  // 如果 a 的值小于 b 的值
            r = a->next;          // 保存 a 的下一个节点
            a->next = C->next;    // 将 a 插入到链表 C 的头部
            C->next = a;
            a = r;                // a 指向下一个节点
        } else {
            r = b->next;          // 保存 b 的下一个节点
            b->next = C->next;    // 将 b 插入到链表 C 的头部
            C->next = b;
            b = r;                // b 指向下一个节点
        }
    }

    // 处理剩余的节点
    while (a != nullptr) {
        r = a->next;              // 保存 a 的下一个节点
        a->next = C->next;        // 将 a 插入到链表 C 的头部
        C->next = a;
        a = r;                    // a 指向下一个节点
    }

    while (b != nullptr) {
        r = b->next;              // 保存 b 的下一个节点
        b->next = C->next;        // 将 b 插入到链表 C 的头部
        C->next = b;
        b = r;                    // b 指向下一个节点
    }

    return C;  // 返回归并后的链表 C
}

day19

//Day19
//设A和B是两个单链表(带头结点),其中元素递增有序。
//设计一个算法从A和B中的公共元素产生单链表c,要求不破坏A、B的结点。
// 从A和B中的公共元素产生单链表C
LinkList Search_Common(LinkList &A, LinkList &B) {
    LinkList C = new Lnode;  // 创建链表 C 的头结点
    C->next = nullptr;
    LinkList r = C;  // r 指向链表 C 的最后一个节点

    LinkList p = A->next;  // p 指向链表 A 的第一个节点
    LinkList q = B->next;  // q 指向链表 B 的第一个节点

    while (p != nullptr && q != nullptr) {
        if (p->data < q->data) {
            p = p->next;  // 移动 p 指针
        } else if (p->data > q->data) {
            q = q->next;  // 移动 q 指针
        } else {
            // 找到公共元素
            LinkList s = new Lnode;  // 创建新节点
            s->data = p->data;       // 赋值
            r->next = s;             // 将新节点插入到链表 C 的末尾
            r = s;                   // 更新 r 指针
            p = p->next;             // 移动 p 指针
            q = q->next;             // 移动 q 指针
        }
    }

    r->next = nullptr;  // 断开链表 C 的最后一个节点
    return C;  // 返回归并后的链表 C
}

day20

//Day20
//已知两个链表A和B分别表示两个集合,其元素递增有序排列。
//编制函数,求A和B的交集,并存放于A链表中。
//分析:元素递增;不能创建一个新链表,求完交集后,A链表中只有相同的元素(A&B的交集元素)
void Insert_same(LinkList &A, LinkList &B) {
    LinkList p = A->next;  // p 指向链表 A 的第一个节点
    LinkList q = B->next;  // q 指向链表 B 的第一个节点
    LinkList prev = A;     // prev 指向链表 A 的头结点

    while (p != nullptr && q != nullptr) {
        if (p->data < q->data) {
            // 如果 p 的值小于 q 的值,删除 p 节点
            prev->next = p->next;
            delete p;
            p = prev->next;
        } else if (p->data > q->data) {
            // 如果 p 的值大于 q 的值,移动 q 指针
            q = q->next;
        } else {
            // 如果 p 的值等于 q 的值,移动 p 和 q 指针
            prev = p;
            p = p->next;
            q = q->next;
        }
    }

    // 如果 p 还有剩余节点,删除剩余节点
    while (p != nullptr) {
        prev->next = p->next;
        delete p;
        p = prev->next;
    }
}

day21

//Day21
//两个整数序列A=al,a2,a3 ...am和B=b1,b2,b3...,bn已经存入两个单链表中,
//设计一个算法,判断序列B是否是序列A的连续子序列
bool IsSon_L(LinkList &A, LinkList &B){
    LinkList p = A->next;
    LinkList q = B->next;

    while(p != nullptr){
        LinkList temp_p = p;
        LinkList temp_q = q;
        while(temp_p != nullptr && temp_q != nullptr &&temp_p->data == temp_q->data){
            temp_p = temp_p->next;
            temp_q = temp_q->next;
        }

        if(temp_q == nullptr){
            return true;
        }

        p = p->next;
    }
    return false;

}

代码解释

  1. 初始化指针

    • LinkList p = A->next;:将指针 p 指向链表 A 的第一个节点。

    • LinkList q = B->next;:将指针 q 指向链表 B 的第一个节点。

  2. 遍历链表 A

    • while (p != nullptr):当 p 不为 nullptr 时,继续遍历链表 A

  3. 检查子序列

    • LinkList temp_p = p;:保存 p 的当前位置。

    • LinkList temp_q = q;:保存 q 的当前位置。

    • while (temp_p != nullptr && temp_q != nullptr && temp_p->data == temp_q->data):当 temp_p 和 temp_q 都不为 nullptr 且它们的值相等时,继续遍历。

    • if (temp_q == nullptr):如果 temp_q 为 nullptr,说明 B 的所有元素在 A 中按顺序连续出现,返回 true

  4. 继续检查

    • p = p->next;:继续检查 A 的下一个节点。

  5. 返回结果

    • 如果遍历完 A 都没有找到 B 的所有元素按顺序连续出现,返回 false

day22

//Day22
//设计一个算法用于判断带头结点的循环双链表是否对称。
int Symmetry(DLinkList &D){
    DLinkList p = D->next;
    DLinkList q = D->prev;

    while(p != q && q->prev !=p){
        if(p->data == q->data){
            p = p->next;
            q = q->prev;
        }else{
            return 0;
        }
    }
    return 1;
}

详细步骤

  1. 初始化指针

    • DLinkList p = D->next;:将指针 p 指向链表的第一个实际数据结点。

    • DLinkList q = D->prev;:将指针 q 指向链表的最后一个实际数据结点。

  2. 循环条件

    • while(p != q && q->prev != p):当 p 和 q 没有相遇或交叉时,继续循环。

    • p != q:表示 p 和 q 还没有相遇。

    • q->prev != p:表示 q 的前一个结点不是 p,即 p 和 q 还没有交叉。

  3. 比较数据

    • if(p->data == q->data):比较 p 和 q 指向的结点的数据。

    • 如果数据相等,则继续移动指针 p 和 q

    • p = p->next;:将指针 p 向后移动到下一个结点。

    • q = q->prev;:将指针 q 向前移动到前一个结点。

  4. 发现不对称

    • else:如果 p 和 q 指向的结点的数据不相等,则链表不对称。

    • return 0;:返回 0,表示链表不对称。

  5. 链表对称

    • 如果循环结束时没有发现不对称的情况,则链表对称。

    • return 1;:返回 1,表示链表对称。

示例

假设我们有以下循环双链表:

头结点 -> 1 -> 2 -> 3 -> 2 -> 1 -> 头结点
  • 初始时,p 指向 1q 指向 1

  • 第一次循环:比较 1 和 1,相等,p 指向 2q 指向 2

  • 第二次循环:比较 2 和 2,相等,p 指向 3q 指向 3

  • 第三次循环:比较 3 和 3,相等,p 指向 2q 指向 2

  • 第四次循环:比较 2 和 2,相等,p 指向 1q 指向 1

  • 此时,p == q,循环结束。

由于所有对应位置的元素都相等,链表对称,函数返回 1

day23

//Day23
//有两个循环单链表,链表头指针分别为h1和h2,
//编写一个函数将链表h2链接到链表h1之后,
//要求链接后的链表仍保持循环链表的形式
LinkList Link(LinkList &h1, LinkList &h2){
    LinkList p = h1;
    LinkList q = h2;

    while(p->next != h1){
        p = p->next;    //找到h1尾结点的前一个结点
    }
    while(q->next != h2){
        q =q->next;    //找到h2尾结点的前一个结点
    }

    p->next = h2->next;
    q->next = h1;
    return h1;
}
        将 h2 链接到 h1 之后
    p->next = h2->next;  // h1 的尾结点指向 h2 的第一个实际数据结点
    q->next = h1;        // h2 的尾结点指向 h1 的头结点

day24

// Day24
// 设有一个带头结点的的循环单链表,其结点值均为正整数。
// 设计一个算法,反复找出单链表中结点值最小的结点并输出,
// 然后将该结点从中删除直到单链表为空为止,再删除表头结点。
void Del_All(LinkList &L) {
    while (L->next != L) {  // 当链表不为空时
        LinkList minprev = L;
        LinkList min = L->next;
        LinkList prev = L;
        LinkList p = L->next;

        // 找到最小值结点
        while (p != L) {
            if (p->data < min->data) {
                min = p;
                minprev = prev;
            }
            prev = p;
            p = p->next;
        }

        // 输出最小值结点
        cout << min->data << "  ";

        // 删除最小值结点
        minprev->next = min->next;
        delete min;
    }

    // 删除表头结点
    delete L;
    L = NULL;
}

day31

//Day31
//已知一棵二叉树按顺序存储结构进行存储,设计一个算法,
//求编号分别为i和j的两个结点的最近公共祖先结点的值。
//算法思想:不断将较大的i和j取一半,直到i=j,找到了最近的公共祖先结点
int Comn_Ancestor(const vector<int> &tree, int i, int j) {
    while (i != j) {
        if (i > j) {
            i = i / 2;
        } else {
            j = j / 2;
        }
    }
    return tree[i];
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值