一. 时间复杂度:
用程序中语句总的执行次数间接表示程序的运行时间。
以一段简单的 C 语言程序为例,预估出此段程序的运行时间:
for(int i = 0 ; i < n ; i++) //<- 从 0 到 n,执行 n+1 次
{
a++; //<- 从 0 到 n-1,执行 n 次
}
可以看到,这段程序中仅有 2 行代码,其中:
for 循环从 i 的值为 0 一直逐增至 n(注意,循环退出的时候 i 值为 n),因此 for 循环语句执行了 n+1 次;
而循环内部仅有一条语句,a++ 从 i 的值为 0 就开始执行,i 的值每增 1 该语句就执行一次,一直到 i 的值为 n-1,因此,a++ 语句一共执行了 n 次。
因此,整段代码中所有语句共执行了 (n+1)+n 次,即 2n+1 次。数据结构中,每条语句的执行次数,又被称为该语句的频度。整段代码的总执行次数,即整段代码的频度。
2.用大 O 记法的表示方法
格式如下:
O(频度)
其中,这里的频度为最简之后所得的频度。
二. 空间复杂度
和时间复杂度类似,一个算法的空间复杂度,也常用大 O 记法表示。
要知道每一个算法所编写的程序,运行过程中都需要占用大小不等的存储空间,例如:
程序代码本身所占用的存储空间;
程序中如果需要输入输出数据,也会占用一定的存储空间;
程序在运行过程中,可能还需要临时申请更多的存储空间。
对算法的空间复杂度影响最大的,往往是程序运行过程中所申请的临时存储空间。不同的算法所编写出的程序,其运行时申请的临时存储空间通常会有较大不同。
我们先看一个代码:
int[] m = new int[n]
for(i=1; i<=n; ++i)
{
j = i;
j++;
}
这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n);
三.基本数据结构
链表、以及kmp算法的实现
struct student {
string name;
int age;
student* pNext;
};
//链表的实现
void addNode(student* pList, student& newNode) {
student* p= pList;
while (p->pNext) {
p = p->pNext;
}
p->pNext = new student(newNode);
}
void traverseList(student* pList) {
student* p = pList->pNext;
while (p) {
//string name = p->name;
cout << "name:" << p->name << ",age:" << p->age << endl;
p = p->pNext;
}
}
void clearList(student* pList) {
student* p = pList->pNext;
student* curDelElem = NULL;
while (p)
{
curDelElem = p;
p = p->pNext;
cout << "delete " << curDelElem->name << endl;
delete curDelElem;
curDelElem = NULL;
}
}
void mergeTwoList(student* pList1, student* pList2) {
student* elem1 = pList1->pNext;
student* elem2 = pList2->pNext;
student* beforeElem1 = pList1;
student* beforeElem2 = pList2;
while (elem1 && elem2) {
if (elem1->age < elem2->age) {
beforeElem1 = elem1;
elem1 = elem1->pNext;
//string str1 = elem1->name;
//string str2 = elem2->name;
}
else {
string test1;
string test2;
student* addElem = elem2;
elem2 = elem2->pNext;
beforeElem1->pNext = addElem;
addElem->pNext = elem1;
beforeElem1 = addElem;
if(elem1)
test1 = elem1->name;
if (elem2)
test2 = elem2->name;
}
}
if (!elem1 && elem2) {
beforeElem1->pNext = elem2;
beforeElem1 = elem2;
elem2 = elem2->pNext;
}
delete pList2;
}
void test04() {
student* pList1 = new student();
addNode(pList1, student{ "zhang",18 });
addNode(pList1, student{ "li",19 });
addNode(pList1, student{ "wang",25 });
//addNode(pList1, student{ "zhou",30 });
//addNode(pList1, student{ "chen",35 });
//traverseList(pList1);
student* pList2 = new student();
addNode(pList2, student{ "zhao",19 });
addNode(pList2, student{ "liu",21 });
addNode(pList2, student{ "zhu",22 });
addNode(pList2, student{ "xia",40 });
addNode(pList2, student{ "sang",45 });
addNode(pList2, student{ "ge",50 });
mergeTwoList(pList1, pList2);
traverseList(pList1);
}
void test05() {
student* pStart = new student[5];
student* pEnd = pStart;
*pEnd++ = student{ "zhang",18 };
*pEnd++ = student{ "li",19 };
cout << pStart[0].name << endl;
cout << pStart[1].name << endl;
//pEnd = pEnd + 1;
int dis = pEnd - pStart;
}
//队列的实现
//循环队列留一个空位
struct queStudent {
student* base;
int front;
int rear;
};
queStudent creatQue() {
queStudent stuQue1;
stuQue1.base = new student[5];
stuQue1.front = 0;
stuQue1.rear = 0;
return stuQue1;
}
bool isFull(queStudent& que) {
if ((que.rear + 1) % 5 == que.front)//循环队列留一个空位
{
return true;
}
return false;
}
bool isEmpty(queStudent& que) {
if (que.rear == que.front)
{
return true;
}
return false;
}
bool pushQue(queStudent& que, student& elem) {
if (isFull(que))
{
return false;
}
que.base[que.rear] = elem;
que.rear = (que.rear+1) % 5;
}
bool popQue(queStudent& que) {
if (isEmpty(que))
{
return false;
}
cout << "pop " << que.base[que.front].name << endl;
que.front = (que.front + 1) % 5;
}
void test06() {
queStudent stuQue1= creatQue();
int i = 0;
string name = "zhang";
while (!isFull(stuQue1)) {
string curName = name + to_string(i);
pushQue(stuQue1, student{ curName,19 });
i++;
}
if (!isEmpty(stuQue1)) popQue(stuQue1);
pushQue(stuQue1, student{ "li",19 });
while (!isEmpty(stuQue1))
{
popQue(stuQue1);
}
}
//串///
// "qwaefge"
// "aef"
//暴力求相同字串法
int findEqualString(string& mainStr,string& subString) {
if (mainStr.size() < subString.size()) return -1;
int i = 0, j = 0;
while(i < mainStr.size() &&j<subString.size())
{
if (mainStr[i] == subString[j]) {
++i;
++j;
}
else {
i = i - j+1;
j = 0;
}
}
if (j == subString.size()) {
return i - j;
}
return -1;
}
void test07() {
int pos = findEqualString(string("qwaefgeegeewqw"), string("aefge"));
cout << pos << endl;
}
//kmp求相同字串法
//求next数组 string s1("qwaefqwageewqw");
void getNext(string str,int next[]) {
int j = 0, k = -1;
next[0] = -1;
cout << "next:" << -1 << " ";
while (j < str.size() - 1) {
/* if (j == 6)
int aa = 0;*/
if (k == -1 || str[j] == str[k]) {
j=j+1;
k=k+1;
next[j] = k;
cout << k << " ";
}
else{
k = next[k];
}
}
cout << endl;
}
int getSubStrPos(string& s1,string& subStr) {
int next[100] = { -2 };
memset(next, 10, sizeof(next));
getNext(s1, next);
int i = 0;
int j = 0;
while (i < s1.size()&& j<subStr.size()){
if (j == -1 || s1[i] == subStr[j]){
i++;
j++;
}
else {
j = next[j];
}
}
if (j == subStr.size())
return i - j;
return -1;
}
void test08() {
string s1("qwaefqwageewqw");
string s2("fqw");
int pos = getSubStrPos(s1,s2);
int aa = 0;
}