王道线性表算法大题代码总结-看这一篇就够了

第二章算法大题

数组

  1. 从顺序表中删除具有最小值的元素(唯一)
bool Del_Min(sqList &L,ElemType &value) {
    if (L.Length==0) {
        return false;
    }
    value = L.data[0];
    int pos=0;
    for (int i = 1;i < L.length; i ++) {
        i f(L.data[i] < value ) {
            value = L.data[i];
            pos = i;
        }
    }
    L.data[pos] = L.data[L.length-1];
    L.length --;
    return true;
}

2.逆置顺序表

void Reverse (Sqlist &L) {
    Elemtype temp;
    int n = L.length;
    for (int i = 0;i < n/2;i ++) {
        temp = L.data[i];
        L.data[i] = L.data[n-i-1];
        L.data[n-i-1] = temp;
    }
}
  1. 删除线性表值为x的元素
void del_x_l(Sqlist &L,Elemtype x) {
    int k = 0,i;
    for (i = 0;i < L.length;i ++) {
        if (L.data[i] !=x) {
            L.data[k] = L.data[i];k++;
        }
    }
    L.lenth = k;
}
bool Del_s_t2(Sqlist &L,ElemType s,Elemtype t) {
    int i ,j;
    if (i = 0;i < L.length && L.data[i] <s ;i ++) ;
    if (i >= L.length)  return false;
    for (j = i;j < L.length &&L.data[j] <= t; j ++) ;
    for (;j < L.length;j ++,i ++) 
        L.data[i] = L.data[j];
    L.length = i;
    return true;
}

5 删除s-t之间的元素

bool Del_s_t(SqList &L,ElemType s,ElemType t) {
    int i,k =0 ;
    if (L.length==0||s>=t) return false;
    for (i = 0;i <L.length;i ++) {
        if (L.data[i] >= s&&L.data[i] <= t) k++;
        else L.data[i-k]=L.data[i];
    }
    L.length -= k;
    return true;
}

6 从有序顺序表中删除所有值重复的元素

bool Delete_Same(SeqList &L) {
    if (L.length == 0) {
        return false;
    }
    int i ,j ;
    for (i = 0,j = 1;j < L.length;j ++) {
        if(L.data[i] !=L.data[j]) L.data[++i] = L.data[j];
    }
    L.length = i + 1;
    return true;
}

7 将两个有序顺序表合并成新的有序顺序表

bool Merge (SeqList A,SeqList B,SeqList C) {
    if (A.length+B.length>C.maxSize) 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 ++];
        else 
            C.data[k ++] = B.data[j ++];
    }
    while (i < A.length)
        C.data[k ++] = A.data[i ++];
    while (j < B.length) 
        C.data[k ++] = B.data[j ++];
    C.length = k;
    return true;
}

8 A [ m + n ] A[m+n] A[m+n] ( a 1 , a 2 , a 3 , … , a m ) (a_1,a_2,a_3,\dots ,a_m) (a1,a2,a3,,am) ( b 1 , b 2 , b 3 , … , b n ) (b_1,b_2,b_3,\dots,b_n) (b1,b2,b3,,bn) 将B放在A的前面

typedef int DataType;
void Reverse(DataType A[],int left,int right,int arraySize) {
    if (left>=right || right >= arraySize) return;
    int mid = (left + right)/2;
    for (int i = 0;i <= mid-left;i ++) {
        DataType temp = A[left+i];
        A[left+i] = A[right - i];
        A[right-i]=temp;
    }
}
void Exchange(DataType A[],int m,int n,int arraySize) {
    Reverse(A,0,m+n-1,arraySize);
    Reverse(A,0,n-1,arraySize);
    Reverse(A,n,m+n-1,arraySize);
  
}

9 线性表递增有序,用最少的时间在表中查找数值为x的元素,若找到则将其与后继元素位置相交换。若找不到,则将其插入表中并使得表中元素仍递增有序。

void SearchExchangeInsert(ElemType A[],ElemType x) {
    int low = 0,high = n-1,mid;
    while (low <= high) {
        mid = (low+high)/2;
        if (A[mid] == x) break;
        else if (A[mid] < x) low = mid + 1; // 1
        else high = mid - 1;                // 2
    }
    // 若最后一个元素与x相等,则不存在与其后继交换的操作
    if (A[mid] == x&&mid != n-1) {
        t = A[mid];A[mid] = A[mid + 1];A[mid + 1] = t;
    }
    if (low > high) {
        // 关于这里为啥最后是 A[high] 是小于x的:
        // 跳出循环的那一步应该是 mid == high == low;
        // if 是上部 1 处是最后一步,那么A[mid=high=low]<x;
        // if 是 2 , 那么A[mid-1=high]<x;
        for (i = n-1; i > high;i --) {
            A[i+1] = A[i];
        }
        A[i+1] = x;
    }
}

10.【2010年真题】

  1. 算法的基本设计思想:

可将这个问题视为把数组ab转换成数组ba(a代表数组的前 p 个元素,b 代表数组中余下的 n-p 个元素),先将
a 逆置 得到 a − 1 b a^{-1}b a1b,再将 b 逆置得到 a 1 b − 1 a^{_1}b^{-1} a1b1,最后将 a 1 b − 1 a^{_1}b^{-1} a1b1 逆置得到 ba。
设 Reverse 函数执行将数组元素逆置的操作,对 abcdefg 向左循环移动 3 个位置的过程如下:
Reverse(0,p-1)
Reverse(p,n-1)
Reverse(0,n-1)
注: Reverse中,两个参数分别表示数组中待转换元素的始末位置。

  1. 使用C语言描述如下
 void Reverse(int R[],int from int to) {
       int i,temp;
       for (i = 0;i <(to-from+1)/2;i ++) {
           temp = R[from+i];R[from+i] = R[to-i];R[to-i] = temp;
       }
   }
   
   void Converse(int R[],int n,int p) 
   {
       Reverse(R,0,p-1);
       Reverse(R,p,n-1);
       Reverse(R,0,n-1);
   }

11.【2011年真题】

  1. 算法的基本设计思想

分别求两个升序序列 A,B 的中位数,设为 a 和 b,求序列A、B的中位数过程如下:
①:若a==b,则a或b即为,所求中位数,算法结束。
②:若a<b,则舍弃序列A中较小的一半,同时舍弃序列B中较大的一半,要求两次舍弃的长度相等。
③:若a>b,则舍弃序列A中较大的一半,同时舍弃序列B中较小的一半,要求两次舍弃的长度相等
在保留的两个升序序列中,重复过程①,②,③,知道两个序列中均只含一个元素时为止。

  1. 代码
int M_Search(int A[],int B[],int n) {
    int s1 = 0,d1 = n-1,m1,s2 = 0,d2 = n-1,m2;
    while (s1!=d1||s2!=d2) {
        m1 = (s1+d1)/2;
        m2 = (s2+d2)/2;
        if (A[m1] == B[m2]) return A[m1];
        if (A[m1] < B[m2]) {
            if ((s1+d1)%2==0) {
                s1 = m1;d2 = m2;
            } else {
                s1 = m1 + 1;
                d2 = m2;
            }
        }
        else {
            if ((s2+d2)%2 == 0) {
                d1 = m1;
                s2 = m2;
            } else {
                d1 = m1;
                s2 = m2 + 1;
            }
        }
    }
    return A[s1] < B[s2]?A[s1]:B[s2];
}int M_Search(int A[],int B[],int n) {
    int s1 = 0,d1 = n-1,m1,s2 = 0,d2 = n-1,m2;
    while (s1!=d1||s2!=d2) {
        m1 = (s1+d1)/2;
        m2 = (s2+d2)/2;
        if (A[m1] == B[m2]) return A[m1];
        if (A[m1] < B[m2]) {
            if ((s1+d1)%2==0) {
                s1 = m1;d2 = m2;
            } else {
                s1 = m1 + 1;
                d2 = m2;
            }
        }
        else {
            if ((s2+d2)%2 == 0) {
                d1 = m1;
                s2 = m2;
            } else {
                d1 = m1;
                s2 = m2 + 1;
            }
        }
    }
    return A[s1] < B[s2]?A[s1]:B[s2];
}

12.【2014年统考真题】

  1. 算法的基本设计思想

算法的策略是从前向后扫描数组元素,标记出一个可能成为主元素的元素Num。然后重新计数确认Num
是否是主元素。
算法可分为以下两步:
①、选取候选的主元素。依次扫描所给数组中的每个整数,将第一个遇到的整数Num保存到c中,记录Num
的出现次数为1;若遇到的下一个整数仍等于Num,则计数加一,否则计数减一;当计数减到0时,将遇到的下一个
整数保存到c中,计数重新计为1,开始新一轮计数,即从当前位置开始重复上述过程,直到扫描完全部
数组元素。
②、判断c中元素是否是真正的主元素。再次扫描该数组,统计c中元素出现的次数,若大于n/2,则为主元素;
否则序列中不存在主元素。

  1. 算法实现
int Majority(int A[],int n)
{
    int i,c,count = 1;
    c = A[0];
    for (i = 1;i < n;i ++) {
        if (A[i] == c) count ++;
        else
            if (count > 0) count --;
            else {
                c = A[i];count = 1;
            }
    }
    if (count > 0) {
        for (i = count = 0;i < n;i ++) 
            if (A[i] == c) count ++;
    }
    if (count > n/2) return c;
    else return -1;
}

13.【2018年真题】

  1. 算法的基本设计思想

分配一个用于标记的数组B[n],用来记录A中是否出现了1~n中的正整数,B[0]对应正整数1,B[n-1]对应 正整数n,初始化B中全部为0。由于A中含有n个整数,因此可能返回的值是1n+1,当A中n个数恰好为1n时返回 n+1。当数组A中出现了小于等于0或大于n的值时,会导致1n中出现空余位置,返回结果必然在1n中,因此 对于A中出现了小于等于0或大于n的值,可以不采取任何操作。 算法流程:从A[0]开始遍历A,若0<A[i]<=n,则令B[A[i]-1]=1;否则不做任何操作。对A遍历结束后 开始遍历数组B,若能找到第一个满足B[i]==0的下标i,返回i+1,即为结果,此时说明A中未出现 的最小正整数在1~n之间。若B[i]全部不为0,返回i+1。`

  1. 算法实现
int findMissMin(int A[],int n) 
{
    int i,*B;
    B = (int *)malloc(sizeof(int)*n);

    memset(B,0,sizeof(int)*n);
    for (i = 0;i < n;i ++) {
        if (A[i] > 0&&A[i]<=n) 
            B[A[i]-1] = 1;
    }
    for (i = 0;i < n;i ++) 
        if (B[i] == 0) break;
    return i + 1;
}

14.【2020年真题】

  1. 算法的基本设计思想

    ①、使用D_min记录所有已处理的三元组的最小距离,初值为一个足够大的整数。
    ②、集合S1、S2和S3分别保存在数组A、B、C中。数组的下标变量i=j=k=0,
    当i<|S1|<j<|S2|且k<|S3|时,循环执行下面的步骤:
    a) 计算(A[i],B[j],C[k])的距离D;
    b) 若 D<Dmin,更新Dmin=D
    c) 将A[i],B[j],C[k]中的最小值的下标+1;
    ③、输出Dmin,结束。

  2. 算法实现

#define INT_MAX 0x7fffffff
int abs_(int a) 
{
    if (a < 0) return -a;
    else return a;
}

bool xls_min(int a,int b,int c)
{
    if (a <= b&&a <= c) return true;
    return false;
}

int findMinofTrip(int A[],int n,int B[],int m,int C[],int p)
{
    int i = 0,j = 0,k = 0,D_min = INT_MAX,D;
    while (i < n&& j < m&&k < p&&D_min > 0) {
        D = abs_(A[i]-B[j])+abs_(B[j]-C[k])+abs_(C[k]-A[i]);
        if (D<D_min) D_min = D;
        if(xls_min (A[i],B[j],C[k])) i ++;
        else if (xls_min(B[j],C[k],A[i])) j ++;
        else k ++;
    }
    return D_min;
}

链表

  1. 设计一个递归算法,删除不带头结点的单链表L中的所有值为x的结点
void Del_x(Linklist &L,ElemType x)
{
    LNode *p;
    if (L == NULL) {
        return ;
    }
    if (L->data == x) {
        p = L;
        L = L -> next;
        free(p);
        Del_x(L,x);
    } else {
        Del_x(L->next,x);
    }
}
  1. 带头结点删除所有值为x
void Del_x_1(Linklist &L,ElemType x) 
{
    LNode *p = L -> next,*pre = L,*q;
    while (p!=NULL) {
        if (p -> data != x) {
            pre = p;
            p = p -> next;
        } else {
            q = q;
            p = p -> next;
            pre -> next = p;
            free(q);
        }
    }
}

void Del_x_2(Linklist *L,ElemType x) 
{
    LNode *p = L -> next, *r = L,*q;
    while (P != NULL) {
        if (p->data != x) {
            r->next = p;
            r = p;
            p = p->next;
        } else {
            q = p;
            p = p->next;
            free(q);
        }
    }
    r->next = NULL;
}
  1. 设L为带头结点的带链表,实现从头到尾反向输出每个结点的值
void f3(Linklist &L)
{
    print(L);
    printf("\n");
}
void print(Linklist &L)
{
    if (L == NULL) return;
    print(L->next);
    printf("%d ",L->data);
}
  1. 编写带头结点的单链表L中删除一个最小值结点的高效算法
LinkList f4(Linklist L)
{
    LNode *pre=L,*now=L->next,*ans_pre = L,*ans=L->next;
    int Min = INT_MAX;
    while (now != NULL) {
        if (now->data < Min) {
            ans = now;
            ans_pre = pre;
            Min = now->data;
        }
        pre = now;
        now = now->next;
    }
    ans_pre->next = ans->next;
    free(ans);
    return L;
}
  1. 就地逆置带头结点的单链表-空间复杂度为 O ( 1 ) O(1) O(1)
    方法一
Linklist f5(Linklist L)
{
    LNode *now = L->next,*pre=L;
    while (now->next != NULL) {
        pre->data = now->data;
        tmp = now;
        tmp->next = pre;
        pre = now;
        now = now->next;
    } 
    L->next = now;
    return L;
}

方法二

LinkList f5_2(Linklist L)
{
    /**
     * @brief 
     * 将头结点摘下然后从第一节点开始,
     * 依次插入到头结点的后面(头插法)
     */
    LNode *p,*r;
    p = L->next;
    L->next = NULL;
    while (p != NULL) {
        r = p->next;
        p->next = L->next;
        L->next = p;
        p = r;
    }
    return L;
}
  1. 使带头结点的单链表L中的元素递增有序
void f6(Linklist &L)
{
    /**
     * @brief 
     * 想法:遍历链表,将链表中的数据放到堆里面,建堆时间O(n)。
     * 然后扫描重建链表
     * 时间复杂度O(n),空间复杂度O(n)
     */
    LNode *p = L->next,*pre;
    LNode *r = p->next;
    p->next = NULL;
    p = r;
    while (p != NULL) {
        r = p->next;
        pre = L;
        while (pre->next!=NULL&&pre->next->data < p->data) 
        {
            pre = pre->next;
        }
        p->next = pre->next;
        pre->next = p;
        p = r;
    }
}
  1. 删除元素
void f7(Linklist &L,int min,int max)
{   
    LNode *pr = L,*p = L->link;
    while (p != NULL) {
        if (p->data > min&&p->data < max) {
            pr->link = p->link;
            free(p);
            p = pr->link;
        } else {
            pr = p;
            p = p->link;
        }
    }
}
  1. 找出两个链表的公共结点
    自己的方法
LNode f8(Linklist A,Linklist B)
{
    /**
     * @brief 
     * 公共结点之后的全部一样了应该是,所以逆置,倒着找。
     */
    Reverse(A),Reverse(B);
    //逆置函数
    LNode *nowA=A->next,*nowB=B->next;
    while (nowA!=NULL&&nowB!=NULL) {
        if (nowA == nowB) {
            return nowA;
        } else {
            nowA = nowA->nxet;
            nowB = nowB->nxet;
        }
    }
    return NULL;
}

答案

LinkList Search_1st_Common(LinkList L1,LinkList L2)
{
    int len1 = Length(L1),len2 = Length(L2);
    LinkList longList,shortList;
    if (len1 > len2) {
        longList = L1->next;shortList=L2->next;
        dist = len1-len2;
    } else {
        longList = L2->next;shortList = L1->next;
        dist = len2-len1;
    }
    while (dist --) {
        longList = longList->next;
        while (longList == shortList) {
            if (longList != NULL) {
                if (longList == shortList) {
                    return longList;
                } else {
                    longList = longList->next;
                    shortList = shortList->next;
                }
            }
        }
    }
    return NULL;
}
  1. 给定带头结点的单链表,按递增顺序输出单链表各节点的数据元素
    答案

对链表进行遍历,在每次遍历中找出整个链表的最小值袁术,输出并释放结点所占空间;再查找次小值元素,输出并释放空间,如此下去,直至链表为空,最后释放头结点所占存储空间。

  1. 分解单链表A,使得A中含有原表中序号为奇数的元素,而B表中含有其他元素
LinkList f10(Linklist A)
{
    Linklist B = (Linklist)malloc(sizeof(LNode));
    //Linklist B = new Linklist;
    int cnt = 0;
    LNode *nowa = A->next,*pre = A,*nowb = B;
    while (now != NULL)
    {
        cnt ++;
        if (cnt % 2 == 0) {
            nowb->next = nowa;
            nowb = nowb->next;
            LNode *p = nowa; 
            nowa = nowa->next;
            pre = p;
            free(p); 
        } else {
            pre = nowa;
            nowa = nowa->next;
        }
    }
}

答案

LinkList DistCreat_1(LinkList &A)
{
    int i = 0;
    LinkList B = (LinkList)malloc(sizeof(LNode));
    B->next = NULL;
    LNode *ra = A,*rb = B,*p;
    p = A->next;
    A->next = NULL;

    while (p!=NULL) {
        i ++;
        if (i%2) {
            ra->next = p;
            ra = p;
        } else {
            rb->next = p;
            rb = p;
        }
        p = p->next;
    }
    ra->next = NULL;
    rb->next = NULL;
    return B;
}
  1. 将C= { a 1 , b 1 , a 2 , b 2 … a n , b n } \{a_1,b_1,a_2,b_2\dots a_n,b_n\} {a1,b1,a2,b2an,bn}拆分成A和B,使得 A = { a 1 , a 2 , … , a n } A=\{a_1,a_2, \dots ,a_n\} A={a1,a2,,an}, B = { b 1 , b 2 , … , b n } B=\{b_1,b_2, \dots ,b_n\} B={b1,b2,,bn}
    自己写的
void f11(Linklist C)
{
    Linklist A = NULL,B = NULL;
    LNode *now = hc->next,*nowa = A,*nowb = B;
    int x = 0;
    while (now!=NULL) {
        if (!x) {
            nowa->next=now;
            nowa = now;
        } else {
            nowb = B->next;
            B->next = now;
            B->next->next = nowb;
            
        }
        now = now->next;
        x~=x;
    }

答案-这个推荐看一下

LinkList DisCreat_2(LinkList &A)
{
    LinkList B = (LinkList)malloc(sizeof(LNode));
    B->next = NULL;
    LNode *p = A->next,*q;
    LNode *ra = A;
    while (p != NULL)
    {
        ra->next = p;ra = p;
        p = p->next;
        if (p != null) {
            q = p->next;
            p->next = B->next;
            B->next = p;
            p = q;
        }
    }
    ra->next = NULL;
    return B;
}
  1. 去掉数值相同的袁术,使得表中不再有重复的元素
void f12(Linklist L)
{
    LNode *now = L->next,*q;
    if (now == NULL) return ;//自己写的时候忘了
    while (now->next != NULL) {
        q = now->next;
        if (now->data == q->data) {
            now->next = q->next;
            free(q);
        } else {
            now = now->next;
        }
    }
}
  1. 假设有两个递增线性表,合并成一个递减的单链表,要求利用原来的结点
void f13(Linklist A,Linklist B)
{
    LNode *nowa=A->next,aa=A,*nowb=B->next,bb=B;
    Linklist *C=NULL,*hc = NULL;
    while (nowa!=NULL&&nowb!=NULL) {
        if (nowa-data<nowb->data) {
            aa = nowa;
            aa->next = C->next;
            C->next = aa;
            nowa = nowa->next;
        } else {
            bb = nowb;
            bb->next = C->next;
            C->next = bb;
            nowb = nowb->next;
        }
    }
    //这里忘了,当时写的时候就记得有个忘了
    if (nowa) nowb=nowa;
    while (nowb) {
        hc = nowb->next;
        nowb->next=C->next;
        C->next=nowb;
        nowb = hc; 
    }
    free(B);
    free(A);
  1. 从递增有序的A和B中的公共元素产生单链表C,要求不破坏A、B的结点
void f14(Linklist A,Linklist B)
{
    LNode *nowa=A->next,*nowb=B->next;
    Linklist C=NULL;LNode *hc = NULL;
    C->next = hc;//这里忘了写了
    while (nowa!=NULL&&nowb!=NULL) {
        if (nowa->data==nowb->data) {
            LNode tmp=new LNode;
            tmp->data = nowa->data;
            hc->next = tmp;
            hc = hc->next;
            delete(tmp);
            nowa=nowa->next;
            nowb=nowb->next;
        } else if (nowa->data<nowb->data) {
            nowa=nowa->next;
        } eles {
            nowb=nowb->next;
        }
    }
    C->next = NULL;//这里忘了写了
}
  1. 求递增有序的A和B的交集,存放于A链表
Linklist f15(Linklist &A,Linklist &B)
{
    //忘了释放结点了
    LNode *nowa = A->next,*pre = A,*nowb = B->next;
    while (nowa!=NULL&&nowb!=NULL) {
        if (nowa->data==nowb->data) {
            pre = nowa;
            nowa = nowa->next;
            u = nowb;
            nowb = nowb->next;
            free(u)
        } else if (nowa->data > nowb->data) {
            u = nowb;
            nowb = nowb->next;
            free(u);
        } else {
            pre->next = nowa->next;
            LNode *tmp = nowa;
            nowa = nowa->next;
            free(tmp);
        }
    }
    while (nowb) {
        u = nowb;
        nowb = nowb->next;
        free(u);
    }
}
  1. 判断序列B是否是序列A的连续子序列
    自己的答案
bool f16(Linklist A,Linklist B)
{
    bool flag = false;
    LNode *nowa=A->next;
    while (nowa != NULL) {
        LNode *tmpa = nowa,*tmpb = B->next;
        while (tmpa!=NULL&&tmpb!=NULL&&tmpa->data==tmpb->data) {
            tmpa = tmpa->next;
            tmpb = tmpb->next;
        } 
        if (tmpa == NULL&&tmpb == NULL) {
            return true;
        }
        nowa = nowa->next;
    } 
    return false;
}

答案

bool Pattern(LinkList A,LinkList B)
{
    LNode *p=A,*pre = p,*q = B;
    while (p&&q) {
        if (p->data == q->data) {
            p = p->next;
            q = q->next;
        } else {
            pre = pre->next;
            p = pre;
            q = B;
        }
    }
    if (q == NULL) return true;
    else return false;
}
  1. 判断带头结点的循环双链表是否对称
bool f17(DLinklist L) 
{
    DNode *p = L->next,*q = L->prior;
    while (p != q&&p->next != q) {
        if (p -> data == q -> data) {
            p = p->next;
            q = q->prior;
        } else {
            return 0;
        }
    }
    return 1;
}
  1. 编写一个函数将其中一个循环单链表连接到另一个之后
Linklist f18(LinkList &h1,LinkList &h2)
{
    LNode *p,*q;
    p = h1;
    while (p->next != h1) 
        p = p->next;
    q = h2;
    while (q->next != h2)
        q = q->next;
    p->next = h2;
    q->next = h1;
    return h1;
}
  1. 反复找出循环单链表中结点值最小的结点并输出,然后将该结点从中删除
void f19_Del_All(LinkList &L)
{
    LNode *p,*pre,*minp,*minpre;
    while (L->next != L) {
        p = L->next;pre = L;
        minp = p;minpre = pre;
        while (p != L) {
            if (p->data < minp->data) {
                minp = p;minpre = pre;
            }
            pre = p;
            p = p->next;
        }
        printf("%d",mnip->data);
        minpre->next = minp->next;
        free(minp);
    }
    free(L);
}

20.【重点题】
设头指针为L的带头结点的非循环双向链表,其中每个结点有前驱指针和后继指针和数据域,还有一个访问频度域freq。在链表被启用前,其值均初始化为零。每当在链表中进行一次Locate(L,x)运算时,令元素值为x的结点中的freq域的值增加1,并使此链表中结点保持按访问频度非增的顺序排列,同时最近访问的结点排在频度相同的结点前面,以便使频繁访问的结点总是靠近表头。

DlinkList f20(DLinkList &L,ElemType x)
{
    DNode *p = L->next,*q;
    while (p && p->data!=x) {
        p = p->next;
    }
    if (!p) 
        exit(0);
    else {
        p->freq++;
        if (p->pre == L||p->pre->freq > p->freq)
            return p;
        if (p->next != NULL) p->next->pre = p->pred;
        p->pred->next = p->next;
        q = p->pred;
        while (q != L && q->freq <= p->freq) {
            q = q->pred;
        }
        p->next = q->next;
        if (q->next != NULL) q->next->pred = p;
        q->next = p;
    }
    return p;
}
  1. 【2009年真题】
    题目:不改变带有头指针list的链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点。

    1. 算法设计思想

定义两个指针变量p和q,初始时均指向头结点的下一个结点(链表的第一个结点),p指针沿链表移动;当p指针移动到第k个结点时,q指针开始于p指针同步移动;当p指针移动到最后一个结点时,q指针所示结点为倒数第k个结点

  1. 算法实现步骤

直接看代码吧

  1. 算法实现
typedef int ElemType;
typedef struct LNode{
    ElemType data;
    struct LNode *link;
}LNode,*Linklist;
int Search_k(Linklist list,int k)
{
    LNode *p = list->link,*q = list->link;
    int count = 0;
    while (p != NULL) {
        if (count < k) {
            count ++;
        } else {
            q = q->link;
        }
        p = p->link;
    }
    if (count < k) 
        return 0;
    else {
        printf("%d",q->data);
        return 1;
    }
}
  1. 【2012年真题】

题目:设计一个时间上尽可能高效的算法,找出str1和str2所指向两个链表共同后缀的起始位置

  1. 算法的基本设计思想

    1.分别求出两个链表的长度m和n

    2.将两个链表对齐

    3.反复将指针p和q同步向后移动

  2. 算法实现

typedef struct Node {
    char data;
    struct Node *next;
}SNode;
int listlen(SNode *head)
{
    int len = 0;
    while (head->next!=NULL) {
        len ++;
        head = head->next;
    }
    return len;
}

SNode* find_addr(SNode *str1,SNode *str2) 
{
    int m,n;
    SNode *p,*q;
    m = listlen(str1);
    n = listlen(str2);
    for (p = str1;m>n;m--)
        p = p->next;
    for (q = str2;m<n;n--)
        q = q->next;
    while (p->next!=NULL&&p->next !=q->next) {
        p = p->next;
        q = q->next;
    }
    return p->next;  
}
  1. 【2015年真题】

题目:单链表保存m个整数,且 |data| <= n。现要求一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的结点,仅保留第一次出现的结点而删除其余绝对值相等的结点。

  1. 算法基本设计思想:

    使用辅助数组记录链表中已出现的数值,从而只需对链表进行一趟扫描

  2. 使用C语言描述的单链表结点的数据类型定义
    typedef struct node {
        int data;
        struct node *link;
    }NODE;
    typedef NODE *PNODE;
    
  1. 算法实现
     void func (PNODE h,int n){
       PNODE p = h,r;
       int *q,m;
       q = (int *)malloc(sizeof(int)*(n+1));
       for (int i = 0;i < n+1;i ++) 
           *(q+i) = 0;
       while (p->link!=NULL) 
       {
           m = p->link->data>0?p->link->data:-p->link->data;
           if (*(q+m) == 0) {
               *(q+m)=1;
               p = p->link;
           } else {
               r = p->link;
               p->link = r->link;
               free(r);
           }
       }
       free(q);
    }

  1. 【2019年真题】

题目:设计一个空间复杂度为 O(1) 且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表 L’=( a 1 , a n , a 2 , a n − 1 , a 3 , a n − 2 a_1,a_n,a_2,a_{n-1},a_3,a_{n-2} a1,an,a2,an1,a3,an2…)

  1. 算法基本设计思想

    1.先找出链表L的中间结点,为此设置两个指针p和q,指针p每次走一步,指针q每次走两步,当指针q到达链尾时,指针p正好在链表的中间结点;2.然后将L的后半段结点原地逆置;3.从单链表前后两段中依次各取一个结点,按要求重排。

  2. 算法实现


  void change_list(NODE *h)
   {
       NODE *p,*q,*r,*s;
       p = q = h;
       while (q->next != NULL) {
           p = p->next;
           q = q->next;
           if (q->next != NULL) q = q->next;
       }
       q = q->next;
       p->next = NULL;
       while (q != NULL) {
           r = q->next;
           q->next = p->next;
           p->next = q;
           q = r;
       }
       s = h->next;
       q = p->next;
       p->next = NULL;
       while (q != NULL) {
           r = p->next;
           q->next = s->next;
           s->next = q;
           s = q->next;
           q = r;
       }
   }

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的码泰君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值